Merge "Introduce a .winscope extension for all winscope files"
diff --git a/Android.bp b/Android.bp
index f06c35b..62dce7f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -297,6 +297,7 @@
],
include_dirs: [
"frameworks/av/aidl",
+ "frameworks/native/libs/permission/aidl",
"packages/modules/Connectivity/framework/aidl-export",
],
},
@@ -542,6 +543,7 @@
],
include_dirs: [
"frameworks/av/aidl",
+ "frameworks/native/libs/permission/aidl",
"packages/modules/Connectivity/framework/aidl-export",
],
},
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 8cfc024..48ae723 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -113,7 +113,10 @@
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
- include_dirs: ["frameworks/av/aidl"],
+ include_dirs: [
+ "frameworks/av/aidl",
+ "frameworks/native/libs/permission/aidl",
+ ],
},
}
@@ -200,7 +203,10 @@
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
- include_dirs: ["frameworks/av/aidl"],
+ include_dirs: [
+ "frameworks/av/aidl",
+ "frameworks/native/libs/permission/aidl",
+ ],
},
}
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/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index a2dc1c2..452bb0a 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -29,6 +29,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -82,7 +83,7 @@
private static class TestWindow extends BaseIWindow {
final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
- final InsetsState mRequestedVisibility = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsState mOutInsetsState = new InsetsState();
final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
@@ -102,7 +103,7 @@
long startTime = SystemClock.elapsedRealtimeNanos();
session.addToDisplay(this, mLayoutParams, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mRequestedVisibility, inputChannel,
+ Display.DEFAULT_DISPLAY, mRequestedVisibilities, inputChannel,
mOutInsetsState, mOutControls);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
state.addExtraResult("add", elapsedTimeNsOfAdd);
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 5801972..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;
@@ -131,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() {
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 1d66beb..db23a6d 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -59,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;
@@ -1479,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/core/java/com/android/internal/view/InputBindResult.aidl b/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl
similarity index 72%
copy from core/java/com/android/internal/view/InputBindResult.aidl
copy to apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl
index 7ff5c4e..bb15011 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2008 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.
@@ -14,6 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package android.app.tare;
-parcelable InputBindResult;
+ /**
+ * IPC interface that supports the app-facing {@link #EconomyManager} api.
+ * {@hide}
+ */
+interface IEconomyManager {
+}
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..9572808 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);
}
/**
@@ -2602,7 +2603,7 @@
final int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
if (callingUid != uid && !UserHandle.isCore(callingUid)) {
throw new SecurityException("Uid " + callingUid
- + " cannot query hasScheduleExactAlarm for uid " + uid);
+ + " cannot query hasScheduleExactAlarm for package " + packageName);
}
return (uid > 0) ? hasScheduleExactAlarmInternal(packageName, uid) : false;
}
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/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 4fb0b71..f0745f3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -696,7 +696,6 @@
@VisibleForTesting
class PendingJobComparator implements Comparator<JobStatus> {
- private final SparseBooleanArray mUidHasEjCache = new SparseBooleanArray();
private final SparseLongArray mEarliestRegEnqueueTimeCache = new SparseLongArray();
/**
@@ -705,14 +704,11 @@
@GuardedBy("mLock")
@VisibleForTesting
void refreshLocked() {
- mUidHasEjCache.clear();
mEarliestRegEnqueueTimeCache.clear();
for (int i = 0; i < mPendingJobs.size(); ++i) {
final JobStatus job = mPendingJobs.get(i);
final int uid = job.getSourceUid();
- if (job.isRequestedExpeditedJob()) {
- mUidHasEjCache.put(uid, true);
- } else {
+ if (!job.isRequestedExpeditedJob()) {
final long earliestEnqueueTime =
mEarliestRegEnqueueTimeCache.get(uid, Long.MAX_VALUE);
mEarliestRegEnqueueTimeCache.put(uid,
@@ -742,9 +738,7 @@
return o1EJ ? -1 : 1;
}
}
- final boolean uid1HasEj = mUidHasEjCache.get(o1.getSourceUid());
- final boolean uid2HasEj = mUidHasEjCache.get(o2.getSourceUid());
- if ((uid1HasEj || uid2HasEj) && (o1EJ || o2EJ)) {
+ if (o1EJ || o2EJ) {
// We MUST prioritize EJs ahead of regular jobs within a single app. Since we do
// that, in order to satisfy the transitivity constraint of the comparator, if
// any UID has an EJ, we must ensure that the EJ is ordered ahead of the regular
@@ -765,9 +759,13 @@
} else if (uid1EarliestRegEnqueueTime > uid2EarliestRegEnqueueTime) {
return 1;
}
- } else if (o1EJ && uid1EarliestRegEnqueueTime < o2.enqueueTime) {
+ } else if (o1EJ && uid1EarliestRegEnqueueTime <= o2.enqueueTime) {
+ // Include = to ensure that if we sorted an EJ ahead of a regular job at time X
+ // then we make sure to sort it ahead of all regular jobs at time X.
return -1;
- } else if (o2EJ && uid2EarliestRegEnqueueTime < o1.enqueueTime) {
+ } else if (o2EJ && uid2EarliestRegEnqueueTime <= o1.enqueueTime) {
+ // Include = to ensure that if we sorted an EJ ahead of a regular job at time X
+ // then we make sure to sort it ahead of all regular jobs at time X.
return 1;
}
}
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/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 7f09e71..74ed334 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -196,7 +196,6 @@
final int eventId, @Nullable String tag) {
final long now = System.currentTimeMillis();
final Ledger ledger = getLedgerLocked(userId, pkgName);
- final boolean wasSolvent = getBalanceLocked(userId, pkgName) > 0;
final int eventType = getEventType(eventId);
switch (eventType) {
@@ -400,12 +399,16 @@
SparseArrayMap<String, OngoingEvent> ongoingEvents =
mCurrentOngoingEvents.get(userId, pkgName);
if (ongoingEvents == null) {
- Slog.wtf(TAG, "No ongoing transactions :/");
+ // This may occur if TARE goes from disabled to enabled while an event is already
+ // occurring.
+ Slog.w(TAG, "No ongoing transactions for <" + userId + ">" + pkgName);
return;
}
final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
if (ongoingEvent == null) {
- Slog.wtf(TAG, "Nonexistent ongoing transaction "
+ // This may occur if TARE goes from disabled to enabled while an event is already
+ // occurring.
+ Slog.w(TAG, "Nonexistent ongoing transaction "
+ eventToString(eventId) + (tag == null ? "" : ":" + tag)
+ " for <" + userId + ">" + pkgName + " ended");
return;
@@ -768,6 +771,15 @@
SystemClock.elapsedRealtime() + timeToThresholdMs);
}
+ @GuardedBy("mLock")
+ void tearDownLocked() {
+ mLedgers.clear();
+ mCurrentNarcsInCirculation = 0;
+ mCurrentOngoingEvents.clear();
+ mBalanceThresholdAlarmListener.dropAllAlarmsLocked();
+ mLedgerCleanupAlarmListener.dropAllAlarmsLocked();
+ }
+
@VisibleForTesting
static class OngoingEvent {
public final long startTimeElapsed;
@@ -987,6 +999,12 @@
}
@GuardedBy("mLock")
+ void dropAllAlarmsLocked() {
+ mAlarmQueue.clear();
+ setNextAlarmLocked(0);
+ }
+
+ @GuardedBy("mLock")
protected abstract void processExpiredAlarmLocked(int userId, @NonNull String packageName);
@Override
@@ -1069,6 +1087,13 @@
final ActionAffordabilityNote note =
new ActionAffordabilityNote(bill, listener, mCompleteEconomicPolicy);
if (actionAffordabilityNotes.add(note)) {
+ if (!mIrs.isEnabled()) {
+ // When TARE isn't enabled, we always say something is affordable. We also don't
+ // want to silently drop affordability change listeners in case TARE becomes enabled
+ // because then clients will be in an ambiguous state.
+ note.setNewAffordability(true);
+ return;
+ }
note.recalculateModifiedPrice(mCompleteEconomicPolicy, userId, pkgName);
note.setNewAffordability(
getBalanceLocked(userId, pkgName) >= note.getCachedModifiedPrice());
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
index a627de6..712e13e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
@@ -40,7 +40,16 @@
super();
mIrs = irs;
mChargingTracker = new ChargingTracker();
- mChargingTracker.startTracking(irs.getContext());
+ }
+
+ @Override
+ public void setup() {
+ mChargingTracker.startTracking(mIrs.getContext());
+ }
+
+ @Override
+ public void tearDown() {
+ mChargingTracker.stopTracking(mIrs.getContext());
}
@Override
@@ -84,6 +93,10 @@
mCharging = batteryManager.isCharging();
}
+ public void stopTracking(@NonNull Context context) {
+ context.unregisterReceiver(this);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
index 20b9c70..37b0aa8 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
@@ -40,7 +40,16 @@
mIrs = irs;
mPowerManager = irs.getContext().getSystemService(PowerManager.class);
mDeviceIdleTracker = new DeviceIdleTracker();
- mDeviceIdleTracker.startTracking(irs.getContext());
+ }
+
+ @Override
+ public void setup() {
+ mDeviceIdleTracker.startTracking(mIrs.getContext());
+ }
+
+ @Override
+ public void tearDown() {
+ mDeviceIdleTracker.stopTracking(mIrs.getContext());
}
@Override
@@ -81,6 +90,10 @@
mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
}
+ void stopTracking(@NonNull Context context) {
+ context.unregisterReceiver(this);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index f08dd24..fa14d10 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -157,11 +157,21 @@
}
@CallSuper
- void onSystemServicesReady() {
+ void setup() {
for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
if (modifier != null) {
- modifier.onSystemServicesReady();
+ modifier.setup();
+ }
+ }
+ }
+
+ @CallSuper
+ void tearDown() {
+ for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
+ final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
+ if (modifier != null) {
+ modifier.tearDown();
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index cfc6645..67d7a95 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -22,29 +22,39 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.tare.IEconomyManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryManagerInternal;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.SparseSetArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -72,8 +82,10 @@
private final BatteryManagerInternal mBatteryManagerInternal;
private final PackageManager mPackageManager;
- private final CompleteEconomicPolicy mCompleteEconomicPolicy;
private final Agent mAgent;
+ private final CompleteEconomicPolicy mCompleteEconomicPolicy;
+ private final ConfigObserver mConfigObserver;
+ private final EconomyManagerStub mEconomyManagerStub;
@NonNull
@GuardedBy("mLock")
@@ -83,8 +95,8 @@
@GuardedBy("mLock")
private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
- @GuardedBy("mLock")
- private boolean mIsSetup;
+ private volatile boolean mIsEnabled;
+ private volatile int mBootPhase;
// In the range [0,100] to represent 0% to 100% battery.
@GuardedBy("mLock")
private int mCurrentBatteryLevel;
@@ -173,45 +185,27 @@
mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
mPackageManager = context.getPackageManager();
+ mEconomyManagerStub = new EconomyManagerStub();
mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
mAgent = new Agent(this, mCompleteEconomicPolicy);
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
- context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
- final IntentFilter pkgFilter = new IntentFilter();
- pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- pkgFilter.addDataScheme("package");
- context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
- final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_ADDED);
- context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+ mConfigObserver = new ConfigObserver(mHandler, context);
publishLocalService(EconomyManagerInternal.class, new LocalService());
}
@Override
public void onStart() {
-
+ publishBinderService(Context.RESOURCE_ECONOMY_SERVICE, mEconomyManagerStub);
}
@Override
public void onBootPhase(int phase) {
+ mBootPhase = phase;
+
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- synchronized (mLock) {
- mCurrentBatteryLevel = getCurrentBatteryLevel();
- // TODO: base on if we have anything persisted
- final boolean isFirstSetup = true;
- if (isFirstSetup) {
- mHandler.post(this::setupEconomy);
- } else {
- mIsSetup = true;
- }
- scheduleUnusedWealthReclamationLocked();
- mCompleteEconomicPolicy.onSystemServicesReady();
- }
+ mConfigObserver.start();
+ setupEverything();
}
}
@@ -238,6 +232,10 @@
/ 100;
}
+ boolean isEnabled() {
+ return mIsEnabled;
+ }
+
void onBatteryLevelChanged() {
synchronized (mLock) {
final int newBatteryLevel = getCurrentBatteryLevel();
@@ -387,11 +385,67 @@
mPkgCache = mPackageManager.getInstalledPackages(0);
}
- private void setupEconomy() {
+ private void registerReceivers() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+ getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
+ final IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ pkgFilter.addDataScheme("package");
+ getContext()
+ .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
+
+ final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+ userFilter.addAction(Intent.ACTION_USER_ADDED);
+ getContext()
+ .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+ }
+
+ /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
+ private void setupHeavyWork() {
synchronized (mLock) {
loadInstalledPackageListLocked();
- mAgent.grantBirthrightsLocked();
- mIsSetup = true;
+ // TODO: base on if we have anything persisted
+ final boolean isFirstSetup = true;
+ if (isFirstSetup) {
+ mAgent.grantBirthrightsLocked();
+ }
+ }
+ }
+
+ private void setupEverything() {
+ if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || !mIsEnabled) {
+ return;
+ }
+ synchronized (mLock) {
+ registerReceivers();
+ mCurrentBatteryLevel = getCurrentBatteryLevel();
+ mHandler.post(this::setupHeavyWork);
+ scheduleUnusedWealthReclamationLocked();
+ mCompleteEconomicPolicy.setup();
+ }
+ }
+
+ private void tearDownEverything() {
+ if (mIsEnabled) {
+ return;
+ }
+ synchronized (mLock) {
+ mAgent.tearDownLocked();
+ mCompleteEconomicPolicy.tearDown();
+ mHandler.post(() -> {
+ // Never call out to AlarmManager with the lock held. This sits below AM.
+ AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
+ if (alarmManager != null) {
+ alarmManager.cancel(mUnusedWealthReclamationListener);
+ }
+ });
+ mPkgCache.clear();
+ mUidToPackageCache.clear();
+ getContext().unregisterReceiver(mBroadcastReceiver);
}
}
@@ -428,6 +482,37 @@
}
}
+ /**
+ * Binder stub trampoline implementation
+ */
+ final class EconomyManagerStub extends IEconomyManager.Stub {
+ /**
+ * "dumpsys" infrastructure
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
+
+ if (!ArrayUtils.isEmpty(args)) {
+ String arg = args[0];
+ if ("-h".equals(arg) || "--help".equals(arg)) {
+ dumpHelp(pw);
+ return;
+ } else if (arg.length() > 0 && arg.charAt(0) == '-') {
+ pw.println("Unknown option: " + arg);
+ return;
+ }
+ }
+
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ dumpInternal(new IndentingPrintWriter(pw, " "));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+ }
+
private final class LocalService implements EconomyManagerInternal {
@Override
public void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
@@ -447,6 +532,9 @@
@Override
public boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill) {
+ if (!mIsEnabled) {
+ return true;
+ }
// TODO: take temp-allowlist into consideration
long requiredBalance = 0;
final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
@@ -466,6 +554,9 @@
@Override
public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
+ if (!mIsEnabled) {
+ return;
+ }
synchronized (mLock) {
mAgent.noteInstantaneousEventLocked(userId, pkgName, eventId, tag);
}
@@ -474,6 +565,9 @@
@Override
public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
+ if (!mIsEnabled) {
+ return;
+ }
synchronized (mLock) {
final long nowElapsed = SystemClock.elapsedRealtime();
mAgent.noteOngoingEventLocked(userId, pkgName, eventId, tag, nowElapsed);
@@ -483,6 +577,9 @@
@Override
public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
@Nullable String tag) {
+ if (!mIsEnabled) {
+ return;
+ }
final long nowElapsed = SystemClock.elapsedRealtime();
final long now = System.currentTimeMillis();
synchronized (mLock) {
@@ -490,4 +587,56 @@
}
}
}
+
+ private class ConfigObserver extends ContentObserver {
+ private final ContentResolver mContentResolver;
+
+ ConfigObserver(Handler handler, Context context) {
+ super(handler);
+ mContentResolver = context.getContentResolver();
+ }
+
+ public void start() {
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
+ updateConfig();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ updateConfig();
+ }
+
+ private void updateConfig() {
+ final boolean isTareEnabled = Settings.Global.getInt(mContentResolver,
+ Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
+ if (mIsEnabled != isTareEnabled) {
+ mIsEnabled = isTareEnabled;
+ if (mIsEnabled) {
+ setupEverything();
+ } else {
+ tearDownEverything();
+ }
+ }
+ }
+ }
+
+ private static void dumpHelp(PrintWriter pw) {
+ pw.println("Resource Economy (economy) dump options:");
+ pw.println(" [-h|--help] [package] ...");
+ pw.println(" -h | --help: print this help");
+ pw.println(" [package] is an optional package name to limit the output to.");
+ }
+
+ private void dumpInternal(final IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ pw.print("Current battery level: ");
+ pw.println(mCurrentBatteryLevel);
+
+ mCompleteEconomicPolicy.dump(pw);
+ pw.println();
+
+ mAgent.dumpLocked(pw);
+ }
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
index 6b89b79..311b6cb 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
@@ -60,7 +60,10 @@
return price;
}
- void onSystemServicesReady() {
+ void setup() {
+ }
+
+ void tearDown() {
}
abstract void dump(IndentingPrintWriter pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
index 2ee6459..92a2014a 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -110,7 +110,7 @@
@Override
@GuardedBy("mLock")
- void onSystemServicesReady() {
+ void setup() {
try {
ActivityManager.getService().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
@@ -120,6 +120,18 @@
}
}
+ @Override
+ @GuardedBy("mLock")
+ void tearDown() {
+ try {
+ ActivityManager.getService().unregisterUidObserver(mUidObserver);
+ } catch (RemoteException e) {
+ // ignored; both services live in system_server
+ }
+ mPackageToUidCache.clear();
+ mUidProcStateBucketCache.clear();
+ }
+
/**
* Get the final modified price based on an app's process state.
*
diff --git a/cmds/bootanimation/OWNERS b/cmds/bootanimation/OWNERS
new file mode 100644
index 0000000..b6fb007
--- /dev/null
+++ b/cmds/bootanimation/OWNERS
@@ -0,0 +1,3 @@
+dupin@google.com
+shanh@google.com
+jreck@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 69c9439..4c1476c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6980,7 +6980,7 @@
}
public static interface WallpaperManager.OnColorsChangedListener {
- method public void onColorsChanged(android.app.WallpaperColors, int);
+ method public void onColorsChanged(@Nullable android.app.WallpaperColors, int);
}
public interface ZygotePreload {
@@ -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..96c990d 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";
@@ -8588,8 +8588,10 @@
method public boolean bind(android.os.UpdateEngineCallback);
method public void cancel();
method @WorkerThread public int cleanupAppliedPayload();
+ method public void resetShouldSwitchSlotOnReboot();
method public void resetStatus();
method public void resume();
+ method public void setShouldSwitchSlotOnReboot(@NonNull String);
method public void suspend();
method public boolean unbind();
method public boolean verifyPayloadMetadata(String);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fb481eb..51416b0 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3198,7 +3198,6 @@
public final class SplashScreenView extends android.widget.FrameLayout {
method @Nullable public android.view.View getBrandingView();
- method @ColorInt public int getIconBackgroundColor();
}
public final class StartingWindowInfo implements android.os.Parcelable {
@@ -3217,6 +3216,59 @@
field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR;
}
+ public final class TaskFragmentAppearedInfo implements android.os.Parcelable {
+ method @NonNull public android.view.SurfaceControl getLeash();
+ method @NonNull public android.window.TaskFragmentInfo getTaskFragmentInfo();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentAppearedInfo> CREATOR;
+ }
+
+ public final class TaskFragmentCreationParams implements android.os.Parcelable {
+ method @NonNull public android.os.IBinder getFragmentToken();
+ method @NonNull public android.graphics.Rect getInitialBounds();
+ method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizer();
+ method @NonNull public android.os.IBinder getOwnerToken();
+ method public int getWindowingMode();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentCreationParams> CREATOR;
+ }
+
+ public static final class TaskFragmentCreationParams.Builder {
+ ctor public TaskFragmentCreationParams.Builder(@NonNull android.window.TaskFragmentOrganizerToken, @NonNull android.os.IBinder, @NonNull android.os.IBinder);
+ method @NonNull public android.window.TaskFragmentCreationParams build();
+ method @NonNull public android.window.TaskFragmentCreationParams.Builder setInitialBounds(@NonNull android.graphics.Rect);
+ method @NonNull public android.window.TaskFragmentCreationParams.Builder setWindowingMode(int);
+ }
+
+ public final class TaskFragmentInfo implements android.os.Parcelable {
+ method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo);
+ method @NonNull public java.util.List<android.os.IBinder> getActivities();
+ method @NonNull public android.content.res.Configuration getConfiguration();
+ method @NonNull public android.os.IBinder getFragmentToken();
+ method @NonNull public android.graphics.Point getPositionInParent();
+ method @NonNull public android.window.WindowContainerToken getToken();
+ method public int getWindowingMode();
+ method public boolean hasRunningActivity();
+ method public boolean isEmpty();
+ method public boolean isVisible();
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentInfo> CREATOR;
+ }
+
+ public class TaskFragmentOrganizer extends android.window.WindowOrganizer {
+ ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
+ method @NonNull public java.util.concurrent.Executor getExecutor();
+ method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
+ method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentAppearedInfo);
+ method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
+ method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
+ method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);
+ method @CallSuper public void registerOrganizer();
+ method @CallSuper public void unregisterOrganizer();
+ }
+
+ public final class TaskFragmentOrganizerToken implements android.os.Parcelable {
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR;
+ }
+
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder);
@@ -3245,9 +3297,13 @@
public final class WindowContainerTransaction implements android.os.Parcelable {
ctor public WindowContainerTransaction();
+ method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
+ method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
method public int describeContents();
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder);
+ method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
@@ -3255,12 +3311,14 @@
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction);
+ method @NonNull public android.window.WindowContainerTransaction setErrorCallbackToken(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction setFocusable(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setLaunchRoot(@NonNull android.window.WindowContainerToken, @Nullable int[], @Nullable int[]);
method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int);
method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int);
+ method @NonNull public android.window.WindowContainerTransaction startActivityInTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder, @NonNull android.content.Intent, @Nullable android.os.Bundle);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.window.WindowContainerTransaction> CREATOR;
}
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/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..70ee7d7 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 */
@@ -1539,6 +1518,17 @@
getApplication().dispatchActivityPostDestroyed(this);
}
+ private void dispatchActivityConfigurationChanged() {
+ getApplication().dispatchActivityConfigurationChanged(this);
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i = 0; i < callbacks.length; i++) {
+ ((Application.ActivityLifecycleCallbacks) callbacks[i])
+ .onActivityConfigurationChanged(this);
+ }
+ }
+ }
+
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
synchronized (mActivityLifecycleCallbacks) {
@@ -1590,14 +1580,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 +1862,7 @@
dispatchActivityStarted();
- if (mAutoFillResetNeeded) {
- getAutofillManager().onVisibleForAutofill();
- }
+ getAutofillClientController().onActivityStarted();
}
/**
@@ -1949,22 +1932,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 +2013,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 +2225,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 +2328,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 +2559,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 +2596,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) {
@@ -3028,6 +2955,8 @@
// view changes from above.
mActionBar.onConfigurationChanged(newConfig);
}
+
+ dispatchActivityConfigurationChanged();
}
/**
@@ -3908,11 +3837,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 +5527,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 +5580,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 +5665,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 +6397,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 +6714,6 @@
/** @hide */
@Override
- public final ComponentName autofillClientGetComponentName() {
- return getComponentName();
- }
-
- /** @hide */
- @Override
public final ComponentName contentCaptureClientGetComponentName() {
return getComponentName();
}
@@ -7134,12 +7037,6 @@
}
}
- /** @hide */
- @Override
- public final void autofillClientRunOnUiThread(Runnable action) {
- runOnUiThread(action);
- }
-
/**
* Standard implementation of
* {@link android.view.LayoutInflater.Factory#onCreateView} used when
@@ -7198,7 +7095,7 @@
// Handle special cases
switch (args[0]) {
case "--autofill":
- dumpAutofillManager(prefix, writer);
+ getAutofillClientController().dumpAutofillManager(prefix, writer);
return;
case "--contentcapture":
dumpContentCaptureManager(prefix, writer);
@@ -7244,24 +7141,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 +7878,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 +8053,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 +8065,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 +8269,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 +8407,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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3abe4d..4983677 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -371,11 +371,12 @@
@UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
Configuration mConfiguration;
+ @GuardedBy("this")
+ private boolean mUpdateHttpProxyOnBind = false;
@UnsupportedAppUsage
Application mInitialApplication;
@UnsupportedAppUsage
- final ArrayList<Application> mAllApplications
- = new ArrayList<Application>();
+ final ArrayList<Application> mAllApplications = new ArrayList<>();
/**
* Bookkeeping of instantiated backup agents indexed first by user id, then by package name.
* Indexing by user id supports parallel backups across users on system packages as they run in
@@ -1189,8 +1190,18 @@
}
public void updateHttpProxy() {
- ActivityThread.updateHttpProxy(
- getApplication() != null ? getApplication() : getSystemContext());
+ final Application app;
+ synchronized (ActivityThread.this) {
+ app = getApplication();
+ if (null == app) {
+ // The app is not bound yet. Make a note to update the HTTP proxy when the
+ // app is bound.
+ mUpdateHttpProxyOnBind = true;
+ return;
+ }
+ }
+ // App is present, update the proxy inline.
+ ActivityThread.updateHttpProxy(app);
}
public void processInBackground() {
@@ -6657,6 +6668,15 @@
sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
mInitialApplication = app;
+ final boolean updateHttpProxy;
+ synchronized (this) {
+ updateHttpProxy = mUpdateHttpProxyOnBind;
+ // This synchronized block ensures that any subsequent call to updateHttpProxy()
+ // will see a non-null mInitialApplication.
+ }
+ if (updateHttpProxy) {
+ ActivityThread.updateHttpProxy(app);
+ }
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
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..7f849ef 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -205,6 +205,13 @@
*/
default void onActivityPostDestroyed(@NonNull Activity activity) {
}
+
+ /**
+ * Called when the Activity configuration was changed.
+ * @hide
+ */
+ default void onActivityConfigurationChanged(@NonNull Activity activity) {
+ }
}
/**
@@ -554,6 +561,16 @@
}
}
+ /* package */ void dispatchActivityConfigurationChanged(@NonNull Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i = 0; i < callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks) callbacks[i]).onActivityConfigurationChanged(
+ activity);
+ }
+ }
+ }
+
@UnsupportedAppUsage
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
@@ -613,7 +630,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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 249a606..7114d73 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -60,7 +61,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.content.AttributionSource;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -3123,6 +3123,7 @@
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
mContextType = container.mContextType;
+ mContentCaptureOptions = container.mContentCaptureOptions;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ab88e6c..908af96 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6120,28 +6120,29 @@
// change the background bgColor
CharSequence title = action.title;
ColorStateList[] outResultColor = new ColorStateList[1];
- int background = getColors(p).getSecondaryAccentColor();
+ int buttonFillColor = getColors(p).getSecondaryAccentColor();
if (isLegacy()) {
title = ContrastColorUtil.clearColorSpans(title);
} else {
- title = ensureColorSpanContrast(title, background, outResultColor);
+ int notifBackgroundColor = getColors(p).getBackgroundColor();
+ title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
}
button.setTextViewText(R.id.action0, processTextSpans(title));
boolean hasColorOverride = outResultColor[0] != null;
if (hasColorOverride) {
// There's a span spanning the full text, let's take it and use it as the
// background color
- background = outResultColor[0].getDefaultColor();
+ buttonFillColor = outResultColor[0].getDefaultColor();
}
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
- background, mInNightMode);
+ buttonFillColor, mInNightMode);
button.setTextColor(R.id.action0, textColor);
// We only want about 20% alpha for the ripple
final int rippleColor = (textColor & 0x00ffffff) | 0x33000000;
button.setColorStateList(R.id.action0, "setRippleColor",
ColorStateList.valueOf(rippleColor));
button.setColorStateList(R.id.action0, "setButtonBackground",
- ColorStateList.valueOf(background));
+ ColorStateList.valueOf(buttonFillColor));
if (p.mCallStyleActions) {
button.setImageViewIcon(R.id.action0, action.getIcon());
boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
@@ -6174,8 +6175,8 @@
* there exists a full length color span.
* @return the contrasted charSequence
*/
- private CharSequence ensureColorSpanContrast(CharSequence charSequence, int background,
- ColorStateList[] outResultColor) {
+ private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
+ int background, ColorStateList[] outResultColor) {
if (charSequence instanceof Spanned) {
Spanned ss = (Spanned) charSequence;
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
@@ -6195,8 +6196,9 @@
int[] colors = textColor.getColors();
int[] newColors = new int[colors.length];
for (int i = 0; i < newColors.length; i++) {
+ boolean isBgDark = isColorDark(background);
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
- colors[i], background, mInNightMode);
+ colors[i], background, isBgDark);
}
textColor = new ColorStateList(textColor.getStates().clone(),
newColors);
@@ -6215,8 +6217,9 @@
} else if (resultSpan instanceof ForegroundColorSpan) {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
int foregroundColor = originalSpan.getForegroundColor();
+ boolean isBgDark = isColorDark(background);
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
- foregroundColor, background, mInNightMode);
+ foregroundColor, background, isBgDark);
if (fullLength) {
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
resultSpan = null;
@@ -6236,6 +6239,19 @@
}
/**
+ * Determines if the color is light or dark. Specifically, this is using the same metric as
+ * {@link ContrastColorUtil#resolvePrimaryColor(Context, int, boolean)} and peers so that
+ * the direction of color shift is consistent.
+ *
+ * @param color the color to check
+ * @return true if the color has higher contrast with white than black
+ */
+ private static boolean isColorDark(int color) {
+ // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
+ return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
+ }
+
+ /**
* @return Whether we are currently building a notification from a legacy (an app that
* doesn't create material notifications by itself) app.
*/
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/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8d332ab..84752be 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -66,6 +66,7 @@
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemProperties;
+import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -221,6 +222,20 @@
public static final String COMMAND_REAPPLY = "android.wallpaper.reapply";
/**
+ * Command for {@link #sendWallpaperCommand}: reported when the live wallpaper needs to be
+ * frozen.
+ * @hide
+ */
+ public static final String COMMAND_FREEZE = "android.wallpaper.freeze";
+
+ /**
+ * Command for {@link #sendWallpaperCommand}: reported when the live wallapper doesn't need
+ * to be frozen anymore.
+ * @hide
+ */
+ public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze";
+
+ /**
* Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
* @hide
*/
@@ -2316,22 +2331,24 @@
* A {@link android.app.WallpaperColors} object containing a simplified
* color histogram will be given.
*
- * @param colors Wallpaper color info
+ * @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
+ * @see WallpaperService.Engine#onComputeColors()
*/
- void onColorsChanged(WallpaperColors colors, int which);
+ void onColorsChanged(@Nullable WallpaperColors colors, int which);
/**
* Called when colors change.
* A {@link android.app.WallpaperColors} object containing a simplified
* color histogram will be given.
*
- * @param colors Wallpaper color info
+ * @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
* @param userId Owner of the wallpaper
+ * @see WallpaperService.Engine#onComputeColors()
* @hide
*/
- default void onColorsChanged(WallpaperColors colors, int which, int userId) {
+ default void onColorsChanged(@Nullable WallpaperColors colors, int which, int userId) {
onColorsChanged(colors, which);
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index dfdeb2d..9a37d04 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 =
@@ -11018,6 +11022,16 @@
* {@link #EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT} in the provisioning parameters.
* In that case the device owner's control will be limited do denying these permissions.
* <p>
+ * NOTE: On devices running {@link android.os.Build.VERSION_CODES#S} and above, control over
+ * the following permissions are restricted for managed profile owners:
+ * <ul>
+ * <li>Manifest.permission.READ_SMS</li>
+ * </ul>
+ * <p>
+ * A managed profile owner may not grant these permissions (i.e. call this method with any of
+ * the permissions listed above and {@code grantState} of
+ * {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them.
+ * <p>
* Attempts by the admin to grant these permissions, when the admin is restricted from doing
* so, will be silently ignored (no exception will be thrown).
*
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fc4a2b4..e1f6af0 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -658,6 +658,7 @@
float mElevation;
float mAlpha = 1.0f;
+ // TODO: The FLAGS_* below have filled all bits, will need to be refactored.
static final int FLAGS_DISABLED = 0x00000001;
static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
static final int FLAGS_FOCUSABLE = 0x00000010;
@@ -673,6 +674,10 @@
static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
static final int FLAGS_OPAQUE = 0x00008000;
+ // --IMPORTANT-- must update this flag if any below flags extend to further bits.
+ // This flag is used to clear all FLAGS_HAS_* values in mFlags prior to parceling.
+ static final int FLAGS_ALL_CONTROL = 0xffff0000;
+
static final int FLAGS_HAS_MIME_TYPES = 0x80000000;
static final int FLAGS_HAS_MATRIX = 0x40000000;
static final int FLAGS_HAS_ALPHA = 0x20000000;
@@ -689,7 +694,7 @@
static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
static final int FLAGS_HAS_URL_SCHEME = 0x00020000;
static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
- static final int FLAGS_ALL_CONTROL = 0xfff00000;
+ // --IMPORTANT END--
static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID = 0x0001;
static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x0002;
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
index 5694ca8..266e33a 100644
--- a/core/java/android/appwidget/AppWidgetManagerInternal.java
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -19,6 +19,8 @@
import android.annotation.Nullable;
import android.util.ArraySet;
+import java.util.Set;
+
/**
* App widget manager local system service interface.
*
@@ -42,4 +44,16 @@
* @param userId The user that is being unlocked.
*/
public abstract void unlockUser(int userId);
+
+ /**
+ * Updates all widgets, applying changes to Runtime Resource Overlay affecting the specified
+ * target packages.
+ *
+ * @param packageNames The names of all target packages for which an overlay was modified
+ * @param userId The user for which overlay modifications occurred.
+ * @param updateFrameworkRes Whether or not an overlay affected the values of framework
+ * resources.
+ */
+ public abstract void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
+ boolean updateFrameworkRes);
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 65cdca9..1dd32fe 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -1025,6 +1025,10 @@
public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
int value) {
if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
+ if (value < 0) {
+ Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value);
+ return false;
+ }
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
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/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bbb550f..f68a8b2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1096,6 +1096,8 @@
/** Address is either resolvable, non-resolvable or static. */
public static final int ADDRESS_TYPE_RANDOM = 1;
+ private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
+
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1493,6 +1495,10 @@
Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
return false;
}
+ if (NULL_MAC_ADDRESS.equals(mAddress)) {
+ Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
+ return false;
+ }
try {
return service.createBond(
this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index cb3bf29..8ff0181 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -168,6 +168,15 @@
dest.writeByteArray(mManufacturerDataMask);
}
}
+
+ // IRK
+ if (mDeviceAddress != null) {
+ dest.writeInt(mAddressType);
+ dest.writeInt(mIrk == null ? 0 : 1);
+ if (mIrk != null) {
+ dest.writeByteArray(mIrk);
+ }
+ }
}
/**
@@ -187,8 +196,10 @@
if (in.readInt() == 1) {
builder.setDeviceName(in.readString());
}
+ String address = null;
+ // If we have a non-null address
if (in.readInt() == 1) {
- builder.setDeviceAddress(in.readString());
+ address = in.readString();
}
if (in.readInt() == 1) {
ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
@@ -245,6 +256,17 @@
}
}
+ // IRK
+ if (address != null) {
+ final int addressType = in.readInt();
+ if (in.readInt() == 1) {
+ final byte[] irk = new byte[16];
+ in.readByteArray(irk);
+ builder.setDeviceAddress(address, addressType, irk);
+ } else {
+ builder.setDeviceAddress(address, addressType);
+ }
+ }
return builder.build();
}
};
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c02dcfd..ac88c7b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5229,6 +5229,15 @@
public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.app.tare.EconomyManager} instance for understanding economic standing.
+ * @see #getSystemService(String)
+ * @hide
+ * @see android.app.tare.EconomyManager
+ */
+ public static final String RESOURCE_ECONOMY_SERVICE = "tare";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a {@link
* android.service.persistentdata.PersistentDataBlockManager} instance
* for interacting with a storage device that lives across factory resets.
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index dd2080b..2bac066 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -207,7 +207,9 @@
return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
| SAFE_STRING_FLAG_FIRST_LINE);
} else {
- return loadUnsafeLabel(pm);
+ // Trims the label string to the MAX_SAFE_LABEL_LENGTH. This is to prevent that the
+ // system is overwhelmed by an enormous string returned by the application.
+ return TextUtils.trimToSize(loadUnsafeLabel(pm), MAX_SAFE_LABEL_LENGTH);
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c2f3ef0..cd02aed 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3699,6 +3699,17 @@
public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY =
"android.hardware.keystore.app_attest_key";
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * is opted-in to receive per-app compatibility overrides that are applied in
+ * {@link com.android.server.compat.overrides.AppCompatOverridesService}.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_APP_COMPAT_OVERRIDES =
+ "android.software.app_compat_overrides";
+
/** @hide */
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
@@ -9085,6 +9096,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 +9158,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 +9172,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 +9204,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 +9265,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 +9279,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/PackageParserCacheHelper.java b/core/java/android/content/pm/PackageParserCacheHelper.java
index 8212224..e03c3ee 100644
--- a/core/java/android/content/pm/PackageParserCacheHelper.java
+++ b/core/java/android/content/pm/PackageParserCacheHelper.java
@@ -56,6 +56,9 @@
mStrings.clear();
final int poolPosition = mParcel.readInt();
+ if (poolPosition < 0) {
+ throw new IllegalStateException("Invalid string pool position: " + poolPosition);
+ }
final int startPosition = mParcel.dataPosition();
// The pool is at the end of the parcel.
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/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 01c0a88..f727a48 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,6 +18,8 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
import static android.content.pm.parsing.ParsingPackageUtils.validateName;
import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import static android.content.pm.parsing.ParsingUtils.DEFAULT_MIN_SDK_VERSION;
@@ -27,7 +29,6 @@
import android.annotation.NonNull;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.SigningDetails;
import android.content.pm.VerifierInfo;
import android.content.pm.parsing.result.ParseInput;
@@ -78,8 +79,6 @@
* This performs validity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
- *
- * @see PackageParser#parsePackage(File, int)
*/
public static ParseResult<PackageLite> parsePackageLite(ParseInput input,
File packageFile, int flags) {
@@ -506,7 +505,7 @@
}
// Check to see if overlay should be excluded based on system property condition
- if (!PackageParser.checkRequiredSystemProperties(requiredSystemPropertyName,
+ if (!checkRequiredSystemProperties(requiredSystemPropertyName,
requiredSystemPropertyValue)) {
Slog.i(TAG, "Skipping target and overlay pair " + targetPackage + " and "
+ codePath + ": overlay ignored due to required system property: "
@@ -577,7 +576,7 @@
return null;
}
- final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey);
+ final PublicKey publicKey = parsePublicKey(encodedPublicKey);
if (publicKey == null) {
Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
return 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..809a544 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;
@@ -45,8 +47,6 @@
import android.content.pm.PackageInfo;
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;
@@ -90,6 +90,7 @@
import android.os.FileUtils;
import android.os.Parcel;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.ext.SdkExtensions;
@@ -98,6 +99,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.Slog;
@@ -121,7 +123,12 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -274,31 +281,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,19 +329,15 @@
* 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
* {@code flags}. Note that this method does not check whether {@code packageFile}
* has changed since the last parse, it's up to callers to do so.
- *
- * @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 +351,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 +402,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 +423,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 +461,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 +472,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 +535,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 +646,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;
@@ -1060,7 +1073,7 @@
+ " must define a public-key value on first use at "
+ parser.getPositionDescription());
} else if (encodedKey != null) {
- PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
+ PublicKey currentKey = parsePublicKey(encodedKey);
if (currentKey == null) {
Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
+ parser.getPositionDescription() + " key-set "
@@ -1298,8 +1311,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());
@@ -1604,8 +1617,39 @@
}
/**
- * {@link ParseResult} version of
- * {@link PackageParser#computeMinSdkVersion(int, String, int, String[], String[])}
+ * Computes the minSdkVersion to use at runtime. If the package is not
+ * compatible with this platform, populates {@code outError[0]} with an
+ * error message.
+ * <p>
+ * If {@code minCode} is not specified, e.g. the value is {@code null},
+ * then behavior varies based on the {@code platformSdkVersion}:
+ * <ul>
+ * <li>If the platform SDK version is greater than or equal to the
+ * {@code minVers}, returns the {@code mniVers} unmodified.
+ * <li>Otherwise, returns -1 to indicate that the package is not
+ * compatible with this platform.
+ * </ul>
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform
+ * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+ * has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param minVers minSdkVersion number, if specified in the application
+ * manifest, or 1 otherwise
+ * @param minCode minSdkVersion code, if specified in the application
+ * manifest, or {@code null} otherwise
+ * @param platformSdkVersion platform SDK version number, typically
+ * Build.VERSION.SDK_INT
+ * @param platformSdkCodenames array of allowed prerelease SDK codenames
+ * for this platform
+ * @return the minSdkVersion to use at runtime if successful
*/
public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
@Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
@@ -1642,8 +1686,31 @@
}
/**
- * {@link ParseResult} version of
- * {@link PackageParser#computeTargetSdkVersion(int, String, String[], String[])}
+ * Computes the targetSdkVersion to use at runtime. If the package is not
+ * compatible with this platform, populates {@code outError[0]} with an
+ * error message.
+ * <p>
+ * If {@code targetCode} is not specified, e.g. the value is {@code null},
+ * then the {@code targetVers} will be returned unmodified.
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform
+ * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+ * has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param targetVers targetSdkVersion number, if specified in the
+ * application manifest, or 0 otherwise
+ * @param targetCode targetSdkVersion code, if specified in the application
+ * manifest, or {@code null} otherwise
+ * @param platformSdkCodenames array of allowed pre-release SDK codenames
+ * for this platform
+ * @return the targetSdkVersion to use at runtime if successful
*/
public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
@Nullable String targetCode, @NonNull String[] platformSdkCodenames,
@@ -2675,7 +2742,7 @@
R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
String propValue = sa.getString(
R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
- if (!PackageParser.checkRequiredSystemProperties(propName, propValue)) {
+ if (!checkRequiredSystemProperties(propName, propValue)) {
String message = "Skipping target and overlay pair " + target + " and "
+ pkg.getBaseApkPath()
+ ": overlay ignored due to required system property: "
@@ -2798,8 +2865,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());
}
}
}
@@ -2953,6 +3020,114 @@
}
/**
+ * @return {@link PublicKey} of a given encoded public key.
+ */
+ public static final PublicKey parsePublicKey(final String encodedPublicKey) {
+ if (encodedPublicKey == null) {
+ Slog.w(TAG, "Could not parse null public key");
+ return null;
+ }
+
+ try {
+ return parsePublicKey(Base64.decode(encodedPublicKey, Base64.DEFAULT));
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+ return null;
+ }
+ }
+
+ /**
+ * @return {@link PublicKey} of the given byte array of a public key.
+ */
+ public static final PublicKey parsePublicKey(final byte[] publicKey) {
+ if (publicKey == null) {
+ Slog.w(TAG, "Could not parse null public key");
+ return null;
+ }
+
+ final EncodedKeySpec keySpec;
+ try {
+ keySpec = new X509EncodedKeySpec(publicKey);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+ return null;
+ }
+
+ /* First try the key as an RSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a RSA public key.
+ }
+
+ /* Now try it as a ECDSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a ECDSA public key.
+ }
+
+ /* Now try it as a DSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a DSA public key.
+ }
+
+ /* Not a supported key type */
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if both the property name and value are empty or if the given system
+ * property is set to the specified value. Properties can be one or more, and if properties are
+ * more than one, they must be separated by comma, and count of names and values must be equal,
+ * and also every given system property must be set to the corresponding value.
+ * In all other cases, returns {@code false}
+ */
+ public static boolean checkRequiredSystemProperties(@Nullable String rawPropNames,
+ @Nullable String rawPropValues) {
+ if (TextUtils.isEmpty(rawPropNames) || TextUtils.isEmpty(rawPropValues)) {
+ if (!TextUtils.isEmpty(rawPropNames) || !TextUtils.isEmpty(rawPropValues)) {
+ // malformed condition - incomplete
+ Slog.w(TAG, "Disabling overlay - incomplete property :'" + rawPropNames
+ + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+ + " AND requiredSystemPropertyValue to be specified.");
+ return false;
+ }
+ // no valid condition set - so no exclusion criteria, overlay will be included.
+ return true;
+ }
+
+ final String[] propNames = rawPropNames.split(",");
+ final String[] propValues = rawPropValues.split(",");
+
+ if (propNames.length != propValues.length) {
+ Slog.w(TAG, "Disabling overlay - property :'" + rawPropNames
+ + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+ + " AND requiredSystemPropertyValue lists to have the same size.");
+ return false;
+ }
+ for (int i = 0; i < propNames.length; i++) {
+ // Check property value: make sure it is both set and equal to expected value
+ final String currValue = SystemProperties.get(propNames[i]);
+ if (!TextUtils.equals(currValue, propValues[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
*
@@ -2961,12 +3136,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 +3151,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 +3168,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 +3188,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/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 07ec6a8..289716a 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -16,9 +16,10 @@
package android.content.pm.parsing;
+import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.PackageParser;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.XmlResourceParser;
@@ -62,7 +63,7 @@
@NonNull
public static ParseResult unknownTag(String parentTag, ParsingPackage pkg,
XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException {
- if (PackageParser.RIGID_PARSER) {
+ if (RIGID_PARSER) {
return input.error("Bad element under " + parentTag + ": " + parser.getName());
}
Slog.w(TAG, "Unknown element under " + parentTag + ": "
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..668b9cc 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
@@ -16,10 +16,11 @@
package android.content.pm.parsing.component;
+import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+
import android.annotation.NonNull;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageParser;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
@@ -60,19 +61,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) {
@@ -96,8 +98,7 @@
String nodeName = parser.getName();
switch (nodeName) {
case "action": {
- String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
- "name");
+ String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
if (value == null) {
result = input.error("No value supplied for <android:name>");
} else if (value.isEmpty()) {
@@ -112,8 +113,7 @@
break;
}
case "category": {
- String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
- "name");
+ String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
if (value == null) {
result = input.error("No value supplied for <android:name>");
} else if (value.isEmpty()) {
@@ -140,7 +140,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..c4b8b98 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -16,10 +16,10 @@
package android.content.pm.parsing.component;
+import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
import static android.content.pm.parsing.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
-import android.content.pm.PackageParser;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.content.pm.parsing.ParsingPackage;
@@ -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,19 +250,19 @@
}
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) {
+ if (RIGID_PARSER) {
return input.error("No path, pathPrefix, or pathPattern for <path-permission>");
}
@@ -303,7 +308,7 @@
}
if (!havePerm) {
- if (PackageParser.RIGID_PARSER) {
+ if (RIGID_PARSER) {
return input.error(
"No readPermission or writePermission for <path-permission>");
}
@@ -349,18 +354,18 @@
}
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) {
+ if (RIGID_PARSER) {
return input.error(
"No path, pathPrefix, or pathPattern for <path-permission>");
}
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..a0c3f75 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,15 +108,15 @@
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws IllegalArgumentException {
loadDependenciesForSplit(0);
return mCachedAssetManagers[0];
}
@Override
- public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
- // Since we insert the base at position 0, and PackageParser keeps splits separate from
- // the base, we need to adjust the index.
+ public AssetManager getSplitAssetManager(int idx) throws IllegalArgumentException {
+ // Since we insert the base at position 0, and ParsingPackageUtils keeps splits separate
+ // from the base, we need to adjust the index.
loadDependenciesForSplit(idx + 1);
return mCachedAssetManagers[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/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index debc074..d69a9e1 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -48,4 +48,8 @@
void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
boolean suppress);
+
+ void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+
+ void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index b7d95e7..fa7ce11 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -29,6 +29,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.service.SensorPrivacyIndividualEnabledSensorProto;
import android.service.SensorPrivacyToggleSourceProto;
import android.util.ArrayMap;
@@ -247,8 +248,7 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, mContext.getUserId(), mContext.getMainExecutor(),
- listener);
+ addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
}
/**
@@ -283,7 +283,25 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, mContext.getUserId(), executor, listener);
+ Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
+ synchronized (mIndividualListeners) {
+ ISensorPrivacyListener iListener = mIndividualListeners.get(key);
+ if (iListener == null) {
+ iListener = new ISensorPrivacyListener.Stub() {
+ @Override
+ public void onSensorPrivacyChanged(boolean enabled) {
+ executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
+ }
+ };
+ mIndividualListeners.put(key, iListener);
+ }
+
+ try {
+ mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -361,7 +379,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
- return isSensorPrivacyEnabled(sensor, mContext.getUserId());
+ return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
}
/**
@@ -392,7 +410,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable) {
- setSensorPrivacy(source, sensor, enable, mContext.getUserId());
+ setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT);
}
/**
@@ -428,7 +446,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable) {
- setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId());
+ setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT);
}
/**
@@ -463,7 +481,7 @@
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress) {
- suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId());
+ suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT);
}
/**
@@ -590,4 +608,5 @@
throw e.rethrowFromSystemServer();
}
}
+
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c78dd53..b55a1cb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2318,6 +2318,51 @@
new Key<Float>("android.control.zoomRatio", float.class);
/**
+ * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AF_REGIONS_SET =
+ new Key<Boolean>("android.control.afRegionsSet", boolean.class);
+
+ /**
+ * <p>Framework-only private key which informs camera fwk that the AE regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AE_REGIONS_SET =
+ new Key<Boolean>("android.control.aeRegionsSet", boolean.class);
+
+ /**
+ * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AWB_REGIONS_SET =
+ new Key<Boolean>("android.control.awbRegionsSet", boolean.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -3057,6 +3102,21 @@
new Key<Integer>("android.scaler.rotateAndCrop", int.class);
/**
+ * <p>Framework-only private key which informs camera fwk that the scaler crop region
+ * ({@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}) has been set by the client and it need
+ * not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#SCALER_CROP_REGION
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> SCALER_CROP_REGION_SET =
+ new Key<Boolean>("android.scaler.cropRegionSet", boolean.class);
+
+ /**
* <p>Duration each pixel is exposed to
* light.</p>
* <p>If the sensor can't expose this exact duration, it will shorten the
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index bfc1f27..d5a35bc 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -446,10 +446,16 @@
}
}
+ @Override
+ protected void finalize() throws Throwable {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
+ super.finalize();
+ }
+
public void release() {
synchronized (mInterfaceLock) {
- mHandlerThread.quitSafely();
-
if (mSessionProcessor != null) {
try {
mSessionProcessor.deInitSession();
@@ -812,6 +818,8 @@
Log.e(TAG,"Failed to parcel buffer fence!");
}
}
+ parcelImage.width = img.getWidth();
+ parcelImage.height = img.getHeight();
parcelImage.format = img.getFormat();
parcelImage.timestamp = img.getTimestamp();
parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 11b137ca..0bf812e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -696,6 +696,16 @@
mCurrentSession.replaceSessionClose();
}
+ if (mCurrentExtensionSession != null) {
+ mCurrentExtensionSession.release();
+ mCurrentExtensionSession = null;
+ }
+
+ if (mCurrentAdvancedExtensionSession != null) {
+ mCurrentAdvancedExtensionSession.release();
+ mCurrentAdvancedExtensionSession = null;
+ }
+
// TODO: dont block for this
boolean configureSuccess = true;
CameraAccessException pendingException = null;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 537b894..7d29a7d 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -49,8 +49,6 @@
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.annotation.NonNull;
@@ -265,13 +263,6 @@
} catch (ClassCastException e) {
throw new UnsupportedOperationException("Failed casting preview processor!");
}
- if (mClientRepeatingRequestSurface != null) {
- mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
- nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
- mRepeatingRequestImageWriter = ImageWriter.newInstance(
- mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
- CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
- }
mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
repeatingSurfaceInfo.mHeight,
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -285,11 +276,6 @@
mPreviewRequestUpdateProcessor.onImageFormatUpdate(
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
} else {
- if (mClientRepeatingRequestSurface != null) {
- mRepeatingRequestImageWriter = ImageWriter.newInstance(
- mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
- CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
- }
mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
repeatingSurfaceInfo.mHeight,
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -320,7 +306,6 @@
mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth,
surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
mImageExtender.getMaxCaptureStage());
- mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
} else {
// The client doesn't intend to trigger multi-frame capture, however the
// image extender still needs to get initialized and the camera still capture
@@ -367,6 +352,29 @@
}
}
+ private void finishPipelineInitialization() throws RemoteException {
+ if (mClientRepeatingRequestSurface != null) {
+ if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
+ mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
+ nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
+ mRepeatingRequestImageWriter = ImageWriter.newInstance(
+ mClientRepeatingRequestSurface,
+ PREVIEW_QUEUE_SIZE,
+ CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+ } else if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_NONE) {
+ mRepeatingRequestImageWriter = ImageWriter.newInstance(
+ mClientRepeatingRequestSurface,
+ PREVIEW_QUEUE_SIZE,
+ CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+ }
+ }
+ if ((mImageProcessor != null) && (mClientCaptureSurface != null)) {
+ CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(
+ mClientCaptureSurface);
+ mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
+ }
+ }
+
/**
* @hide
*/
@@ -622,11 +630,18 @@
new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
}
+ @Override
+ protected void finalize() throws Throwable {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
+ super.finalize();
+ }
+
/** @hide */
public void release() {
synchronized (mInterfaceLock) {
mInternalRepeatingRequestEnabled = false;
- mHandlerThread.quitSafely();
try {
mPreviewExtender.onDeInit();
@@ -750,6 +765,7 @@
synchronized (mInterfaceLock) {
mCaptureSession = session;
try {
+ finishPipelineInitialization();
CameraExtensionCharacteristics.initializeSession(mInitializeHandler);
} catch (RemoteException e) {
Log.e(TAG, "Failed to initialize session! Extension service does"
@@ -1640,6 +1656,8 @@
Log.e(TAG,"Failed to parcel buffer fence!");
}
}
+ parcelImage.width = img.getWidth();
+ parcelImage.height = img.getHeight();
parcelImage.format = img.getFormat();
parcelImage.timestamp = img.getTimestamp();
parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 950d716b..9acf9bf 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
-import android.hardware.HardwareBuffer;
import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -78,41 +77,20 @@
SurfaceInfo surfaceInfo = new SurfaceInfo();
int nativeFormat = SurfaceUtils.getSurfaceFormat(s);
int dataspace = SurfaceUtils.getSurfaceDataspace(s);
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
+ surfaceInfo.mFormat = nativeFormat;
+ surfaceInfo.mWidth = surfaceSize.getWidth();
+ surfaceInfo.mHeight = surfaceSize.getHeight();
+ surfaceInfo.mUsage = SurfaceUtils.getSurfaceUsage(s);
// Jpeg surfaces cannot be queried for their usage and other parameters
// in the usual way below. A buffer can only be de-queued after the
// producer overrides the surface dimensions to (width*height) x 1.
if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) &&
(dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) {
surfaceInfo.mFormat = ImageFormat.JPEG;
- Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
- surfaceInfo.mWidth = surfaceSize.getWidth();
- surfaceInfo.mHeight = surfaceSize.getHeight();
return surfaceInfo;
}
- HardwareBuffer buffer = null;
- try {
- writer = ImageWriter.newInstance(s, 1);
- img = writer.dequeueInputImage();
- buffer = img.getHardwareBuffer();
- surfaceInfo.mFormat = buffer.getFormat();
- surfaceInfo.mWidth = buffer.getWidth();
- surfaceInfo.mHeight = buffer.getHeight();
- surfaceInfo.mUsage = buffer.getUsage();
- } catch (Exception e) {
- Log.e(TAG, "Failed to query surface, returning defaults!");
- } finally {
- if (buffer != null) {
- buffer.close();
- }
- if (img != null) {
- img.close();
- }
- if (writer != null) {
- writer.close();
- }
- }
-
return surfaceInfo;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 6cbe107..8fd9a6a 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -53,6 +53,7 @@
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
+import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.MandatoryStreamCombination;
import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
import android.hardware.camera2.params.OisSample;
@@ -1708,6 +1709,34 @@
metadata.setGpsLocation((Location) value);
}
});
+ sSetCommandMap.put(CaptureRequest.SCALER_CROP_REGION.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setScalerCropRegion((Rect) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AWB_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAWBRegions((MeteringRectangle[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAFRegions((MeteringRectangle[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAERegions((MeteringRectangle[]) value);
+ }
+ });
}
private boolean setAvailableFormats(int[] value) {
@@ -1777,6 +1806,42 @@
return true;
}
+ private <T> boolean setScalerCropRegion(Rect cropRegion) {
+ if (cropRegion == null) {
+ return false;
+ }
+ setBase(CaptureRequest.SCALER_CROP_REGION_SET, true);
+ setBase(CaptureRequest.SCALER_CROP_REGION, cropRegion);
+ return true;
+ }
+
+ private <T> boolean setAFRegions(MeteringRectangle[] afRegions) {
+ if (afRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+ return true;
+ }
+
+ private <T> boolean setAERegions(MeteringRectangle[] aeRegions) {
+ if (aeRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+ return true;
+ }
+
+ private <T> boolean setAWBRegions(MeteringRectangle[] awbRegions) {
+ if (awbRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+ return true;
+ }
+
private void updateNativeAllocation() {
long currentBufferSize = nativeGetBufferSize(mMetadataPtr);
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 35b5c15..57d8ded 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -105,6 +105,20 @@
}
/**
+ * Get the surface usage bits.
+ *
+ * @param surface The surface to be queried for usage.
+ * @return the native object id of the surface, 0 if surface is not backed by a native object.
+ */
+ public static long getSurfaceUsage(Surface surface) {
+ checkNotNull(surface);
+ try {
+ return nativeDetectSurfaceUsageFlags(surface);
+ } catch (IllegalArgumentException e) {
+ return 0;
+ }
+ }
+ /**
* Get the Surface size.
*
* @param surface The surface to be queried for size.
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index abcc33c..4f20553 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -21,6 +21,7 @@
import android.graphics.Point;
import android.hardware.SensorManager;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.util.IntArray;
import android.util.Slog;
@@ -340,6 +341,28 @@
public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);
/**
+ * Returns the window token of the level of the WindowManager hierarchy to mirror. Returns null
+ * if layer mirroring by SurfaceFlinger should not be performed for the given displayId.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ public abstract IBinder getWindowTokenClientToMirror(int displayId);
+
+ /**
+ * For the given displayId, updates the window token of the level of the WindowManager hierarchy
+ * to mirror. If windowToken is null, then SurfaceFlinger performs no layer mirroring to the
+ * given display.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ public abstract void setWindowTokenClientToMirror(int displayId, IBinder windowToken);
+
+ /**
+ * Returns the default size of the surface associated with the display, or null if the surface
+ * is not provided for layer mirroring by SurfaceFlinger.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ public abstract Point getDisplaySurfaceDefaultSize(int displayId);
+
+ /**
* Describes the requested power state of the display.
*
* This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 71688c7c..0e86f43 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.media.projection.MediaProjection;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
@@ -91,9 +92,16 @@
*/
private int mDisplayIdToMirror = DEFAULT_DISPLAY;
+ /**
+ * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+ * should not be performed.
+ */
+ @Nullable
+ private IBinder mWindowTokenClientToMirror = null;
- // Code below generated by codegen v1.0.20.
+
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -115,7 +123,8 @@
int flags,
@Nullable Surface surface,
@Nullable String uniqueId,
- int displayIdToMirror) {
+ int displayIdToMirror,
+ @Nullable IBinder windowTokenClientToMirror) {
this.mName = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mName);
@@ -135,6 +144,7 @@
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
+ this.mWindowTokenClientToMirror = windowTokenClientToMirror;
// onConstructed(); // You can define this method to get a callback
}
@@ -212,6 +222,15 @@
return mDisplayIdToMirror;
}
+ /**
+ * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+ * should not be performed.
+ */
+ @DataClass.Generated.Member
+ public @Nullable IBinder getWindowTokenClientToMirror() {
+ return mWindowTokenClientToMirror;
+ }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -221,6 +240,7 @@
int flg = 0;
if (mSurface != null) flg |= 0x20;
if (mUniqueId != null) flg |= 0x40;
+ if (mWindowTokenClientToMirror != null) flg |= 0x100;
dest.writeInt(flg);
dest.writeString(mName);
dest.writeInt(mWidth);
@@ -230,6 +250,7 @@
if (mSurface != null) dest.writeTypedObject(mSurface, flags);
if (mUniqueId != null) dest.writeString(mUniqueId);
dest.writeInt(mDisplayIdToMirror);
+ if (mWindowTokenClientToMirror != null) dest.writeStrongBinder(mWindowTokenClientToMirror);
}
@Override
@@ -252,6 +273,7 @@
Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
int displayIdToMirror = in.readInt();
+ IBinder windowTokenClientToMirror = (flg & 0x100) == 0 ? null : (IBinder) in.readStrongBinder();
this.mName = name;
com.android.internal.util.AnnotationValidations.validate(
@@ -272,6 +294,7 @@
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
+ this.mWindowTokenClientToMirror = windowTokenClientToMirror;
// onConstructed(); // You can define this method to get a callback
}
@@ -305,6 +328,7 @@
private @Nullable Surface mSurface;
private @Nullable String mUniqueId;
private int mDisplayIdToMirror;
+ private @Nullable IBinder mWindowTokenClientToMirror;
private long mBuilderFieldsSet = 0L;
@@ -439,10 +463,22 @@
return this;
}
+ /**
+ * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+ * should not be performed.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setWindowTokenClientToMirror(@NonNull IBinder value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x100;
+ mWindowTokenClientToMirror = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull VirtualDisplayConfig build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x100; // Mark builder used
+ mBuilderFieldsSet |= 0x200; // Mark builder used
if ((mBuilderFieldsSet & 0x10) == 0) {
mFlags = 0;
@@ -456,6 +492,9 @@
if ((mBuilderFieldsSet & 0x80) == 0) {
mDisplayIdToMirror = DEFAULT_DISPLAY;
}
+ if ((mBuilderFieldsSet & 0x100) == 0) {
+ mWindowTokenClientToMirror = null;
+ }
VirtualDisplayConfig o = new VirtualDisplayConfig(
mName,
mWidth,
@@ -464,12 +503,13 @@
mFlags,
mSurface,
mUniqueId,
- mDisplayIdToMirror);
+ mDisplayIdToMirror,
+ mWindowTokenClientToMirror);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x100) != 0) {
+ if ((mBuilderFieldsSet & 0x200) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -477,10 +517,10 @@
}
@DataClass.Generated(
- time = 1604456298440L,
- codegenVersion = "1.0.20",
+ time = 1620657851981L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 12557f9..3c3ba59 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) {
@@ -169,31 +169,6 @@
}
/**
- * Request authentication of a crypto object. This call operates the face recognition hardware
- * and starts capturing images. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
- * which point the object is no longer valid. The operation can be canceled by using the
- * provided cancel object.
- *
- * @param crypto object associated with the call or null if none required.
- * @param cancel an object that can be used to cancel authentication
- * @param callback an object to receive authentication events
- * @param handler an optional handler to handle callback events
- * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
- * by
- * <a href="{@docRoot}training/articles/keystore.html">Android
- * Keystore facility</a>.
- * @throws IllegalStateException if the crypto primitive is not initialized.
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
- authenticate(crypto, cancel, callback, handler, mContext.getUserId());
- }
-
- /**
* Use the provided handler thread for events.
*/
private void useHandler(Handler handler) {
@@ -224,8 +199,10 @@
* @throws IllegalStateException if the crypto primitive is not initialized.
* @hide
*/
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) {
+ @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId,
+ boolean isKeyguardBypassEnabled) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -247,7 +224,7 @@
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), isKeyguardBypassEnabled);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
@@ -293,7 +270,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 +278,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 +296,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 +323,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 +831,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 +1105,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..db02a0ef 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -46,7 +46,7 @@
// Authenticate the given sessionId with a face
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
- String opPackageName);
+ String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout.
@@ -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/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index a3be415..dac1b49 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -36,12 +36,10 @@
import android.util.ArrayMap;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -71,32 +69,6 @@
private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
/**
- * A cache of the current device's physical address. When device's HDMI out port
- * is not connected to any device, it is set to {@link #INVALID_PHYSICAL_ADDRESS}.
- *
- * <p>Otherwise it is updated by the {@link ClientHotplugEventListener} registered
- * with {@link com.android.server.hdmi.HdmiControlService} by the
- * {@link #addHotplugEventListener(HotplugEventListener)} and the address is from
- * {@link com.android.server.hdmi.HdmiControlService#getPortInfo()}
- */
- @GuardedBy("mLock")
- private int mLocalPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
-
- private void setLocalPhysicalAddress(int physicalAddress) {
- synchronized (mLock) {
- mLocalPhysicalAddress = physicalAddress;
- }
- }
-
- private int getLocalPhysicalAddress() {
- synchronized (mLock) {
- return mLocalPhysicalAddress;
- }
- }
-
- private final Object mLock = new Object();
-
- /**
* Broadcast Action: Display OSD message.
* <p>Send when the service has a message to display on screen for events
* that need user's attention such as ARC status change.
@@ -972,37 +944,6 @@
mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
mIsSwitchDevice = HdmiProperties.is_switch().orElse(false);
- addHotplugEventListener(new ClientHotplugEventListener());
- }
-
- private final class ClientHotplugEventListener implements HotplugEventListener {
-
- @Override
- public void onReceived(HdmiHotplugEvent event) {
- List<HdmiPortInfo> ports = new ArrayList<>();
- try {
- ports = mService.getPortInfo();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- if (ports.isEmpty()) {
- Log.e(TAG, "Can't find port info, not updating connected status. "
- + "Hotplug event:" + event);
- return;
- }
- // If the HDMI OUT port is plugged or unplugged, update the mLocalPhysicalAddress
- for (HdmiPortInfo port : ports) {
- if (port.getId() == event.getPort()) {
- if (port.getType() == HdmiPortInfo.PORT_OUTPUT) {
- setLocalPhysicalAddress(
- event.isConnected()
- ? port.getAddress()
- : INVALID_PHYSICAL_ADDRESS);
- }
- break;
- }
- }
- }
}
private static boolean hasDeviceType(int[] types, int type) {
@@ -1404,7 +1345,11 @@
*/
@SystemApi
public int getPhysicalAddress() {
- return getLocalPhysicalAddress();
+ try {
+ return mService.getPhysicalAddress();
+ } catch (RemoteException e) {
+ return INVALID_PHYSICAL_ADDRESS;
+ }
}
/**
@@ -1421,7 +1366,7 @@
@SystemApi
public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Objects.requireNonNull(targetDevice);
- int physicalAddress = getLocalPhysicalAddress();
+ int physicalAddress = getPhysicalAddress();
if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
@@ -1442,7 +1387,7 @@
@SystemApi
public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Objects.requireNonNull(targetDevice);
- int physicalAddress = getLocalPhysicalAddress();
+ int physicalAddress = getPhysicalAddress();
if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
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/Environment.java b/core/java/android/os/Environment.java
index 308e6d5..0257408 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -693,6 +693,9 @@
* <p>
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* monitor_storage}
+ * <p>
+ * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
+ * {@link MediaStore} offer better performance.
*
* @see #getExternalStorageState()
* @see #isExternalStorageRemovable()
@@ -993,6 +996,9 @@
* </p>
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* public_picture}
+ * <p>
+ * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
+ * {@link MediaStore} offer better performance.
*
* @param type The type of storage directory to return. Should be one of
* {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f3e0ce9..1bc6495 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1460,15 +1460,15 @@
/** {@hide} */
@VisibleForTesting
public static ParcelFileDescriptor convertToModernFd(FileDescriptor fd) {
- try {
- Context context = AppGlobals.getInitialApplication();
- if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
- // Never convert modern fd for MediaProvider, because this requires
- // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
- return null;
- }
- return MediaStore.getOriginalMediaFormatFileDescriptor(context,
- ParcelFileDescriptor.dup(fd));
+ Context context = AppGlobals.getInitialApplication();
+ if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
+ // Never convert modern fd for MediaProvider, because this requires
+ // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
+ return null;
+ }
+
+ try (ParcelFileDescriptor dupFd = ParcelFileDescriptor.dup(fd)) {
+ return MediaStore.getOriginalMediaFormatFileDescriptor(context, dupFd);
} catch (Exception e) {
Log.d(TAG, "Failed to convert to modern format file descriptor", e);
return null;
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index dfd935d0..018bc6b 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -70,3 +70,6 @@
# Bugreporting
per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS
+
+# UpdateEngine
+per-file *UpdateEngine* = file:/platform/system/update_engine:/OWNERS
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/Process.java b/core/java/android/os/Process.java
index 6bca336..9f37c48 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -34,12 +34,9 @@
import libcore.io.IoUtils;
-import java.io.BufferedReader;
import java.io.FileDescriptor;
-import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
-import java.util.StringTokenizer;
import java.util.concurrent.TimeoutException;
/**
@@ -1472,43 +1469,4 @@
}
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
-
- /**
- * Checks if a process corresponding to a specific pid owns any file locks.
- * @param pid The process ID for which we want to know the existence of file locks.
- * @return true If the process holds any file locks, false otherwise.
- * @throws IOException if /proc/locks can't be accessed.
- *
- * @hide
- */
- public static boolean hasFileLocks(int pid) throws Exception {
- BufferedReader br = null;
-
- try {
- br = new BufferedReader(new FileReader("/proc/locks"));
- String line;
-
- while ((line = br.readLine()) != null) {
- StringTokenizer st = new StringTokenizer(line);
-
- for (int i = 0; i < 5 && st.hasMoreTokens(); i++) {
- String str = st.nextToken();
- try {
- if (i == 4 && Integer.parseInt(str) == pid) {
- return true;
- }
- } catch (NumberFormatException nfe) {
- throw new Exception("Exception parsing /proc/locks at \" "
- + line + " \", token #" + i);
- }
- }
- }
-
- return false;
- } finally {
- if (br != null) {
- br.close();
- }
- }
- }
}
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 5a48242..3e01c53 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -409,10 +409,11 @@
/**
* Resets the bootable flag on the non-current partition and all internal
- * update_engine state. This can be used after an unwanted payload has been
- * successfully applied and the device has not yet been rebooted to signal
- * that we no longer want to boot into that updated system. After this call
- * completes, update_engine will no longer report
+ * update_engine state. Note this call will clear the entire update
+ * progress. So a subsequent {@link #applyPayload} will apply the update
+ * from scratch.
+ *
+ * <p>After this call completes, update_engine will no longer report
* {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
* notification that rebooting into the new system is possible.
*/
@@ -425,6 +426,39 @@
}
/**
+ * Sets the A/B slot switch for the next boot after applying an ota update. If
+ * {@link #applyPayload} hasn't switched the slot, the updater APP can call
+ * this API to switch the slot and apply the update on next boot.
+ *
+ * @param payloadMetadataFilename the location of the metadata without the
+ * {@code file://} prefix.
+ */
+ public void setShouldSwitchSlotOnReboot(@NonNull String payloadMetadataFilename) {
+ try {
+ mUpdateEngine.setShouldSwitchSlotOnReboot(payloadMetadataFilename);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Resets the boot slot to the source/current slot, without cancelling the
+ * update progress. This can be called after the update is installed, and to
+ * prevent the device from accidentally taking the update when it reboots.
+ *
+ * This is useful when users don't want to take the update immediately; or
+ * the updater determines some condition hasn't met, e.g. insufficient space
+ * for boot.
+ */
+ public void resetShouldSwitchSlotOnReboot() {
+ try {
+ mUpdateEngine.resetShouldSwitchSlotOnReboot();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Unbinds the last bound callback function.
*/
public boolean unbind() {
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/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 9ab6955..4a94c32 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -16,7 +16,7 @@
package android.permission;
-import android.content.AttributionSource;
+import android.content.AttributionSourceState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -87,7 +87,7 @@
boolean isAutoRevokeExempted(String packageName, int userId);
- void registerAttributionSource(in AttributionSource source);
+ void registerAttributionSource(in AttributionSourceState source);
- boolean isRegisteredAttributionSource(in AttributionSource source);
+ boolean isRegisteredAttributionSource(in AttributionSourceState source);
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index a52ede8..63bcc9c 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1177,7 +1177,7 @@
// enforcement we need to replace the binder with a unique one.
final AttributionSource registeredSource = source.withToken(new Binder());
try {
- mPermissionManager.registerAttributionSource(registeredSource);
+ mPermissionManager.registerAttributionSource(registeredSource.asState());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -1196,7 +1196,7 @@
*/
public boolean isRegisteredAttributionSource(@NonNull AttributionSource source) {
try {
- return mPermissionManager.isRegisteredAttributionSource(source);
+ return mPermissionManager.isRegisteredAttributionSource(source.asState());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
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..4dfa6c3 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);
@@ -6399,8 +6410,15 @@
public static final String DATA_ROAMING = Global.DATA_ROAMING;
/**
- * Setting to record the input method used by default, holding the ID
- * of the desired method.
+ * Stores {@link android.view.inputmethod.InputMethodInfo#getId()} of the input method
+ * service that is currently selected.
+ *
+ * <p>Although the name {@link #DEFAULT_INPUT_METHOD} implies that there is a concept of
+ * <i>default</i> input method, in reality this setting is no more or less than the
+ * <strong>currently selected</strong> input method. This setting can be updated at any
+ * time as a result of user-initiated and system-initiated input method switching.</p>
+ *
+ * <p>Use {@link ComponentName#unflattenFromString(String)} to parse the stored value.</p>
*/
@Readable
public static final String DEFAULT_INPUT_METHOD = "default_input_method";
@@ -7219,6 +7237,13 @@
"touch_exploration_granted_accessibility_services";
/**
+ * Is talkback service enabled or not. 0 == no, 1 == yes
+ *
+ * @hide
+ */
+ public static final String WEAR_TALKBACK_ENABLED = "wear_talkback_enabled";
+
+ /**
* Whether the Global Actions Panel is enabled.
* @hide
*/
@@ -9985,15 +10010,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 +10044,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
@@ -10129,6 +10165,61 @@
@Readable
public static final String GAME_DASHBOARD_ALWAYS_ON = "game_dashboard_always_on";
+
+ /**
+ * For this device state, no specific auto-rotation lock setting should be applied.
+ * If the user toggles the auto-rotate lock in this state, the setting will apply to the
+ * previously valid device state.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_IGNORED = 0;
+ /**
+ * For this device state, the setting for auto-rotation is locked.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_LOCKED = 1;
+ /**
+ * For this device state, the setting for auto-rotation is unlocked.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_UNLOCKED = 2;
+
+ /**
+ * The different settings that can be used as values with
+ * {@link #DEVICE_STATE_ROTATION_LOCK}.
+ * @hide
+ */
+ @IntDef(prefix = {"DEVICE_STATE_ROTATION_LOCK_"}, value = {
+ DEVICE_STATE_ROTATION_LOCK_IGNORED,
+ DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DeviceStateRotationLockSetting {
+ }
+
+ /**
+ * Rotation lock setting keyed on device state.
+ *
+ * This holds a serialized map using int keys that represent Device States and value of
+ * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
+ * device state.
+ *
+ * Serialized as key0:value0:key1:value1:...:keyN:valueN.
+ *
+ * Example: "0:1:1:2:2:1"
+ * This example represents a map of:
+ * <ul>
+ * <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+ * <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+ * <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String DEVICE_STATE_ROTATION_LOCK =
+ "device_state_rotation_lock";
+
/**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
@@ -13405,6 +13496,21 @@
= "forced_app_standby_for_small_battery_enabled";
/**
+ * Whether to enable the TARE subsystem as a whole or not.
+ * 1 means enable, 0 means disable.
+ *
+ * @hide
+ */
+ public static final String ENABLE_TARE = "enable_tare";
+
+ /**
+ * Default value for {@link #ENABLE_TARE}.
+ *
+ * @hide
+ */
+ public static final int DEFAULT_ENABLE_TARE = 0;
+
+ /**
* Whether or not to enable the User Absent, Radios Off feature on small battery devices.
* Type: int (0 for false, 1 for true)
* Default: 0
@@ -16271,18 +16377,19 @@
public static final int RETAIL_MODE_RETAIL = 1;
/**
- * The play store availability.
+ * The play store availability on companion phone.
* @hide
*/
- public static final String PLAY_STORE_AVAILABILITY = "play_store_availability";
+ public static final String PHONE_PLAY_STORE_AVAILABILITY =
+ "phone_play_store_availability";
- // Possible play store availability states
+ // Possible phone play store availability states
/** @hide */
- public static final int PLAY_STORE_AVAILABILITY_UNKNOWN = 0;
+ public static final int PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN = 0;
/** @hide */
- public static final int PLAY_STORE_AVAILABLE = 1;
+ public static final int PHONE_PLAY_STORE_AVAILABLE = 1;
/** @hide */
- public static final int PLAY_STORE_UNAVAILABLE = 2;
+ public static final int PHONE_PLAY_STORE_UNAVAILABLE = 2;
/**
* Whether the bug report is enabled.
@@ -16666,6 +16773,80 @@
* @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";
+
+ /**
+ * Controls the gestures feature.
+ * @hide
+ */
+ public static final String MASTER_GESTURES_ENABLED = "master_gestures_enabled";
+
+ /**
+ * Whether or not ungaze is enabled.
+ * @hide
+ */
+ public static final String UNGAZE_ENABLED = "ungaze_enabled";
+
+ /**
+ * The device's battery saver mode, which can be one of the following:
+ * -{@link BATTERY_SAVER_MODE_NONE}
+ * -{@link BATTERY_SAVER_MODE_LIGHT}
+ * -{@link BATTERY_SAVER_MODE_TRADITIONAL_WATCH}
+ * -{@link BATTERY_SAVER_MODE_TIME_ONLY}
+ * -{@link BATTERY_SAVER_MODE_CUSTOM}
+ * @hide
+ */
+ public static final String BATTERY_SAVER_MODE = "battery_saver_mode";
+
+ /**
+ * Not in Battery Saver Mode
+ * @hide
+ */
+ public static final int BATTERY_SAVER_MODE_NONE = 0;
+ /**
+ * In Lightweight Battery Saver Mode
+ * @hide
+ */
+ public static final int BATTERY_SAVER_MODE_LIGHT = 1;
+ /**
+ * In Traditional Watch Mode Battery Saver Mode
+ * @hide
+ */
+ public static final int BATTERY_SAVER_MODE_TRADITIONAL_WATCH = 2;
+ /**
+ * In Time-only Mode Battery Saver Mode
+ * @hide
+ */
+ public static final int BATTERY_SAVER_MODE_TIME_ONLY = 3;
+ /**
+ * Partner's Battery Saver implementation is being used
+ * @hide
+ */
+ public static final int BATTERY_SAVER_MODE_CUSTOM = 4;
+
+ /**
+ * The maximum ambient mode duration when an activity is allowed to auto resume.
+ * @hide
+ */
+ public static final String WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS =
+ "wear_activity_auto_resume_timeout_ms";
+
+ /**
+ * If burn in protection is enabled.
+ * @hide
+ */
+ public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection";
+
+ /**
+ * Whether the device has combined location setting enabled.
+ * @hide
+ */
+ public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable";
}
}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index a435239..e3bb589 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -72,8 +72,7 @@
@SystemApi
public abstract class HotwordDetectionService extends Service {
private static final String TAG = "HotwordDetectionService";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final long UPDATE_TIMEOUT_MILLIS = 5000;
@@ -151,9 +150,7 @@
@Override
public void updateState(PersistableBundle options, SharedMemory sharedMemory,
IRemoteCallback callback) throws RemoteException {
- if (DBG) {
- Log.d(TAG, "#updateState");
- }
+ Log.v(TAG, "#updateState" + (callback != null ? " with callback" : ""));
HotwordDetectionService.this.onUpdateStateInternal(
options,
sharedMemory,
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index fb540b1..02294e5 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -47,7 +47,7 @@
**/
class SoftwareHotwordDetector extends AbstractHotwordDetector {
private static final String TAG = SoftwareHotwordDetector.class.getSimpleName();
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final IVoiceInteractionManagerService mManagerService;
private final HotwordDetector.Callback mCallback;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index fe1fcfc..4bf6049 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -16,6 +16,8 @@
package android.service.wallpaper;
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MSCALE_Y;
import static android.graphics.Matrix.MSKEW_X;
@@ -42,12 +44,14 @@
import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
+import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Build;
@@ -56,6 +60,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -73,6 +78,7 @@
import android.view.InputEventReceiver;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MotionEvent;
import android.view.PixelCopy;
import android.view.Surface;
@@ -199,6 +205,12 @@
boolean mVisible;
boolean mReportedVisible;
boolean mDestroyed;
+ // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false
+ // after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once
+ // mScreenshotSurfaceControl isn't null. When this happens, then Engine is notified through
+ // doVisibilityChanged that main wallpaper surface is no longer visible and the wallpaper
+ // host receives onVisibilityChanged(false) callback.
+ private boolean mFrozenRequested = false;
// Current window state.
boolean mCreated;
@@ -224,10 +236,9 @@
final ClientWindowFrames mWinFrames = new ClientWindowFrames();
final Rect mDispatchedContentInsets = new Rect();
final Rect mDispatchedStableInsets = new Rect();
- final Rect mFinalSystemInsets = new Rect();
- final Rect mFinalStableInsets = new Rect();
DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
final InsetsState mInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
private final Point mSurfaceSize = new Point();
@@ -264,6 +275,8 @@
SurfaceControl mSurfaceControl = new SurfaceControl();
SurfaceControl mBbqSurfaceControl;
BLASTBufferQueue mBlastBufferQueue;
+ private SurfaceControl mScreenshotSurfaceControl;
+ private Point mScreenshotSize = new Point();
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
@@ -776,8 +789,10 @@
WallpaperColors color = colors.get(i);
RectF area = regions.get(i);
if (color == null || area == null) {
- Log.wtf(TAG, "notifyLocalColorsChanged null values. color: "
- + color + " area " + area);
+ if (DEBUG) {
+ Log.e(TAG, "notifyLocalColorsChanged null values. color: "
+ + color + " area " + area);
+ }
continue;
}
try {
@@ -995,8 +1010,8 @@
InputChannel inputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
- mDisplay.getDisplayId(), mInsetsState, inputChannel, mInsetsState,
- mTempControls) < 0) {
+ mDisplay.getDisplayId(), mRequestedVisibilities, inputChannel,
+ mInsetsState, mTempControls) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -1033,6 +1048,9 @@
.build();
updateSurfaceDimming();
}
+ // Propagate transform hint from WM so we can use the right hint for the
+ // first frame.
+ mBbqSurfaceControl.setTransformHint(mSurfaceControl.getTransformHint());
Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
mSurfaceSize.y, mFormat);
// If blastSurface == null that means it hasn't changed since the last
@@ -1344,11 +1362,15 @@
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (visible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
}
void reportVisibility() {
+ if (mScreenshotSurfaceControl != null && mVisible) {
+ if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change");
+ return;
+ }
if (!mDestroyed) {
mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
@@ -1365,6 +1387,10 @@
updateSurface(true, false, false);
}
onVisibilityChanged(visible);
+ if (mReportedVisible && mFrozenRequested) {
+ if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update");
+ freeze();
+ }
}
}
}
@@ -1825,6 +1851,9 @@
void doCommand(WallpaperCommand cmd) {
Bundle result;
if (!mDestroyed) {
+ if (COMMAND_FREEZE.equals(cmd.action) || COMMAND_UNFREEZE.equals(cmd.action)) {
+ updateFrozenState(/* frozenRequested= */ !COMMAND_UNFREEZE.equals(cmd.action));
+ }
result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z,
cmd.extras, cmd.sync);
} else {
@@ -1839,6 +1868,159 @@
}
}
+ private void updateFrozenState(boolean frozenRequested) {
+ if (mIWallpaperEngine.mWallpaperManager.getWallpaperInfo() == null
+ // Procees the unfreeze command in case the wallaper became static while
+ // being paused.
+ && frozenRequested) {
+ if (DEBUG) Log.v(TAG, "Ignoring the freeze command for static wallpapers");
+ return;
+ }
+ mFrozenRequested = frozenRequested;
+ boolean isFrozen = mScreenshotSurfaceControl != null;
+ if (mFrozenRequested == isFrozen) {
+ return;
+ }
+ if (mFrozenRequested) {
+ freeze();
+ } else {
+ unfreeze();
+ }
+ }
+
+ private void freeze() {
+ if (!mReportedVisible || mDestroyed) {
+ // Screenshot can't be taken until visibility is reported to the wallpaper host.
+ return;
+ }
+ if (!showScreenshotOfWallpaper()) {
+ return;
+ }
+ // Prevent a wallpaper host from rendering wallpaper behind a screeshot.
+ doVisibilityChanged(false);
+ // Remember that visibility is requested since it's not guaranteed that
+ // mWindow#dispatchAppVisibility will be called when letterboxed application with
+ // wallpaper background transitions to the Home screen.
+ mVisible = true;
+ }
+
+ private void unfreeze() {
+ cleanUpScreenshotSurfaceControl();
+ if (mVisible) {
+ doVisibilityChanged(true);
+ }
+ }
+
+ private void cleanUpScreenshotSurfaceControl() {
+ // TODO(b/194399558): Add crossfade transition.
+ if (mScreenshotSurfaceControl != null) {
+ new SurfaceControl.Transaction()
+ .remove(mScreenshotSurfaceControl)
+ .show(mBbqSurfaceControl)
+ .apply();
+ mScreenshotSurfaceControl = null;
+ }
+ }
+
+ void scaleAndCropScreenshot() {
+ if (mScreenshotSurfaceControl == null) {
+ return;
+ }
+ if (mScreenshotSize.x <= 0 || mScreenshotSize.y <= 0) {
+ Log.w(TAG, "Unexpected screenshot size: " + mScreenshotSize);
+ return;
+ }
+ // Don't scale down and using the same scaling factor for both dimensions to
+ // avoid stretching wallpaper image.
+ float scaleFactor = Math.max(1, Math.max(
+ ((float) mSurfaceSize.x) / mScreenshotSize.x,
+ ((float) mSurfaceSize.y) / mScreenshotSize.y));
+ int diffX = ((int) (mScreenshotSize.x * scaleFactor)) - mSurfaceSize.x;
+ int diffY = ((int) (mScreenshotSize.y * scaleFactor)) - mSurfaceSize.y;
+ if (DEBUG) {
+ Log.v(TAG, "Adjusting screenshot: scaleFactor=" + scaleFactor
+ + " diffX=" + diffX + " diffY=" + diffY + " mSurfaceSize=" + mSurfaceSize
+ + " mScreenshotSize=" + mScreenshotSize);
+ }
+ new SurfaceControl.Transaction()
+ .setMatrix(
+ mScreenshotSurfaceControl,
+ /* dsdx= */ scaleFactor, /* dtdx= */ 0,
+ /* dtdy= */ 0, /* dsdy= */ scaleFactor)
+ .setWindowCrop(
+ mScreenshotSurfaceControl,
+ new Rect(
+ /* left= */ diffX / 2,
+ /* top= */ diffY / 2,
+ /* right= */ diffX / 2 + mScreenshotSize.x,
+ /* bottom= */ diffY / 2 + mScreenshotSize.y))
+ .setPosition(mScreenshotSurfaceControl, -diffX / 2, -diffY / 2)
+ .apply();
+ }
+
+ private boolean showScreenshotOfWallpaper() {
+ if (mDestroyed || mSurfaceControl == null || !mSurfaceControl.isValid()) {
+ if (DEBUG) Log.v(TAG, "Failed to screenshot wallpaper: surface isn't valid");
+ return false;
+ }
+
+ final Rect bounds = new Rect(0, 0, mSurfaceSize.x, mSurfaceSize.y);
+ if (bounds.isEmpty()) {
+ Log.w(TAG, "Failed to screenshot wallpaper: surface bounds are empty");
+ return false;
+ }
+
+ if (mScreenshotSurfaceControl != null) {
+ Log.e(TAG, "Screenshot is unexpectedly not null");
+ // Destroying previous screenshot since it can have different size.
+ cleanUpScreenshotSurfaceControl();
+ }
+
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ SurfaceControl.captureLayers(
+ new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+ // Needed because SurfaceFlinger#validateScreenshotPermissions
+ // uses this parameter to check whether a caller only attempts
+ // to screenshot itself when call doesn't come from the system.
+ .setUid(Process.myUid())
+ .setChildrenOnly(false)
+ .setSourceCrop(bounds)
+ .build());
+
+ if (screenshotBuffer == null) {
+ Log.w(TAG, "Failed to screenshot wallpaper: screenshotBuffer is null");
+ return false;
+ }
+
+ final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+
+ // TODO(b/194399558): Add crossfade transition.
+ mScreenshotSurfaceControl = new SurfaceControl.Builder()
+ .setName("Wallpaper snapshot for engine " + this)
+ .setFormat(hardwareBuffer.getFormat())
+ .setParent(mSurfaceControl)
+ .setSecure(screenshotBuffer.containsSecureLayers())
+ .setCallsite("WallpaperService.Engine.showScreenshotOfWallpaper")
+ .setBLASTLayer()
+ .build();
+
+ mScreenshotSize.set(mSurfaceSize.x, mSurfaceSize.y);
+
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(hardwareBuffer);
+
+ t.setBuffer(mScreenshotSurfaceControl, graphicBuffer);
+ t.setColorSpace(mScreenshotSurfaceControl, screenshotBuffer.getColorSpace());
+ // Place on top everything else.
+ t.setLayer(mScreenshotSurfaceControl, Integer.MAX_VALUE);
+ t.show(mScreenshotSurfaceControl);
+ t.hide(mBbqSurfaceControl);
+ t.apply();
+
+ return true;
+ }
+
void reportSurfaceDestroyed() {
if (mSurfaceCreated) {
mSurfaceCreated = false;
@@ -2161,6 +2343,7 @@
final boolean reportDraw = message.arg1 != 0;
mEngine.updateSurface(true, false, reportDraw);
mEngine.doOffsetsChanged(true);
+ mEngine.scaleAndCropScreenshot();
} break;
case MSG_WINDOW_MOVED: {
// Do nothing. What does it mean for a Wallpaper to move?
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1f11d10..1a7ec7f 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -782,7 +782,7 @@
int spanStart = runStart;
int spanLimit;
- if (mSpanned == null) {
+ if (mSpanned == null || runStart == runLimit) {
spanLimit = runLimit;
} else {
int target = after ? offset + 1 : offset;
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/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index f74990a..c7d9b9c 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -209,7 +209,7 @@
if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
- verityDigest, apk.length(), signatureInfo);
+ verityDigest, apk.getChannel().size(), signatureInfo);
}
return new VerifiedSigner(
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 4d1402a..b07b522 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -211,7 +211,7 @@
if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
- verityDigest, apk.length(), signatureInfo);
+ verityDigest, apk.getChannel().size(), signatureInfo);
}
return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
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/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 7e6175c..6a24de25 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -368,7 +368,7 @@
SignatureInfo signatureInfo) throws SecurityException {
try {
byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
- apk.length(), signatureInfo);
+ apk.getChannel().size(), signatureInfo);
VerityBuilder.VerityResult verity = VerityBuilder.generateApkVerityTree(apk,
signatureInfo, new ByteBufferFactory() {
@Override
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index b0a5992..c7c465d 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -90,7 +90,7 @@
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
long signingBlockSize =
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
- long dataSize = apk.length() - signingBlockSize;
+ long dataSize = apk.getChannel().size() - signingBlockSize;
int[] levelOffset = calculateVerityLevelOffset(dataSize);
int merkleTreeSize = levelOffset[levelOffset.length - 1];
@@ -108,7 +108,7 @@
@NonNull SignatureInfo signatureInfo, @NonNull ByteBuffer footerOutput)
throws IOException {
footerOutput.order(ByteOrder.LITTLE_ENDIAN);
- generateApkVerityHeader(footerOutput, apk.length(), DEFAULT_SALT);
+ generateApkVerityHeader(footerOutput, apk.getChannel().size(), DEFAULT_SALT);
long signingBlockSize =
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
generateApkVerityExtensions(footerOutput, signatureInfo.apkSigningBlockOffset,
@@ -339,11 +339,11 @@
eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
consumeByChunk(digester,
DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField,
- apk.length() - offsetAfterEocdCdOffsetField),
+ apk.getChannel().size() - offsetAfterEocdCdOffsetField),
MMAP_REGION_SIZE_BYTES);
// 5. Pad 0s up to the nearest 4096-byte block before hashing.
- int lastIncompleteChunkSize = (int) (apk.length() % CHUNK_SIZE_BYTES);
+ int lastIncompleteChunkSize = (int) (apk.getChannel().size() % CHUNK_SIZE_BYTES);
if (lastIncompleteChunkSize != 0) {
digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index e1a4402..0257e55 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Path;
@@ -873,18 +874,147 @@
}
/**
+ * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
+ * which is used to get the related cutout configs for that display.
+ *
+ * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
+ * display if there are different type of cutouts on each display.
+ * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
+ * and the system will load the default configs for main built-in display.
+ */
+ private static int getDisplayCutoutConfigIndex(Resources res, String displayUniqueId) {
+ int index = -1;
+ if (displayUniqueId == null || displayUniqueId.isEmpty()) {
+ return index;
+ }
+ final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
+ final int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ if (displayUniqueId.equals(ids[i])) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Gets the display cutout by the given display unique id.
+ *
+ * Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static String getDisplayCutoutPath(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
+ if (index >= 0 && index < array.length) {
+ return array[index];
+ }
+ return res.getString(R.string.config_mainBuiltInDisplayCutout);
+ }
+
+ /**
+ * Gets the display cutout approximation rect by the given display unique id.
+ *
+ * Loads the default config {@link R.string#config_mainBuiltInDisplayCutoutRectApproximation} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final String[] array = res.getStringArray(
+ R.array.config_displayCutoutApproximationRectArray);
+ if (index >= 0 && index < array.length) {
+ return array[index];
+ }
+ return res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation);
+ }
+
+ /**
+ * Gets whether to mask a built-in display cutout of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default config {@link R.bool#config_maskMainBuiltInDisplayCutout} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
+ boolean maskCutout;
+ if (index >= 0 && index < array.length()) {
+ maskCutout = array.getBoolean(index, false);
+ } else {
+ maskCutout = res.getBoolean(R.bool.config_maskMainBuiltInDisplayCutout);
+ }
+ array.recycle();
+ return maskCutout;
+ }
+
+ /**
+ * Gets whether to fill a built-in display cutout of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default config{@link R.bool#config_fillMainBuiltInDisplayCutout} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
+ boolean fillCutout;
+ if (index >= 0 && index < array.length()) {
+ fillCutout = array.getBoolean(index, false);
+ } else {
+ fillCutout = res.getBoolean(R.bool.config_fillMainBuiltInDisplayCutout);
+ }
+ array.recycle();
+ return fillCutout;
+ }
+
+ /**
+ * Gets the waterfall cutout by the given display unique id.
+ *
+ * Loads the default waterfall dimens if {@link R.array#config_displayUniqueIdArray} is not set.
+ * {@link R.dimen#waterfall_display_left_edge_size},
+ * {@link R.dimen#waterfall_display_top_edge_size},
+ * {@link R.dimen#waterfall_display_right_edge_size},
+ * {@link R.dimen#waterfall_display_bottom_edge_size}
+ */
+ private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
+ Insets insets;
+ final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray);
+ if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) {
+ final int resourceId = array.getResourceId(index, 0);
+ final TypedArray waterfall = res.obtainTypedArray(resourceId);
+ insets = Insets.of(
+ waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0),
+ waterfall.getDimensionPixelSize(1 /* waterfall top edge size */, 0),
+ waterfall.getDimensionPixelSize(2 /* waterfall right edge size */, 0),
+ waterfall.getDimensionPixelSize(3 /* waterfall bottom edge size */, 0));
+ waterfall.recycle();
+ } else {
+ insets = loadWaterfallInset(res);
+ }
+ array.recycle();
+ return insets;
+ }
+
+ /**
* Creates the display cutout according to
* @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
* rectangle-base approximation of the cutout.
*
* @hide
*/
- public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
- int displayHeight) {
- return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
- res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
+ public static DisplayCutout fromResourcesRectApproximation(Resources res,
+ String displayUniqueId, int displayWidth, int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId),
+ getDisplayCutoutApproximationRect(res, displayUniqueId),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res)).second;
+ getWaterfallInsets(res, displayUniqueId)).second;
}
/**
@@ -892,11 +1022,11 @@
*
* @hide
*/
- public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
- return pathAndDisplayCutoutFromSpec(
- res.getString(R.string.config_mainBuiltInDisplayCutout), null,
+ public static Path pathFromResources(Resources res, String displayUniqueId, int displayWidth,
+ int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), null,
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res)).first;
+ getWaterfallInsets(res, displayUniqueId)).first;
}
/**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f4539c2..8c2348c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -53,6 +53,7 @@
import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.InputChannel;
@@ -720,14 +721,15 @@
int displayId, in IDisplayWindowInsetsController displayWindowInsetsController);
/**
- * Called when a remote process modifies insets on a display window container.
+ * Called when a remote process updates the requested visibilities of insets on a display window
+ * container.
*/
- void modifyDisplayWindowInsets(int displayId, in InsetsState state);
+ void updateDisplayWindowRequestedVisibilities(int displayId, in InsetsVisibilities vis);
/**
* Called to get the expected window insets.
*
- * @return {@code true} if system bars are always comsumed.
+ * @return {@code true} if system bars are always consumed.
*/
boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
out InsetsState outInsetsState);
@@ -873,4 +875,10 @@
* @see android.window.WindowProviderService#getLaunchedDisplayId
*/
int getImeDisplayId();
+
+ /**
+ * Control if we should enable task snapshot features on this device.
+ * @hide
+ */
+ void setTaskSnapshotEnabled(boolean enabled);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7bad5cb..a6abed0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -32,6 +32,7 @@
import android.view.WindowManager;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -46,12 +47,12 @@
*/
interface IWindowSession {
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
- in int viewVisibility, in int layerStackId, in InsetsState requestedVisibility,
+ in int viewVisibility, in int layerStackId, in InsetsVisibilities requestedVisibilities,
out InputChannel outInputChannel, out InsetsState insetsState,
out InsetsSourceControl[] activeControls);
int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in int userId,
- in InsetsState requestedVisibility, out InputChannel outInputChannel,
+ in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out InsetsState insetsState);
@@ -285,10 +286,9 @@
oneway void updateTapExcludeRegion(IWindow window, in Region region);
/**
- * Called when the client has changed the local insets state, and now the server should reflect
- * that new state.
+ * Updates the requested visibilities of insets.
*/
- oneway void insetsModified(IWindow window, in InsetsState state);
+ oneway void updateRequestedVisibilities(IWindow window, in InsetsVisibilities visibilities);
/**
* Called when the system gesture exclusion has changed.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1a9b34e..2ed705a 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -107,9 +107,12 @@
boolean hasControl);
/**
- * Called when insets have been modified by the client and should be reported back to WM.
+ * Called when the requested visibilities of insets have been modified by the client.
+ * The visibilities should be reported back to WM.
+ *
+ * @param visibilities A collection of the requested visibilities.
*/
- void onInsetsModified(InsetsState insetsState);
+ void updateRequestedVisibilities(InsetsVisibilities visibilities);
/**
* @return Whether the host has any callbacks it wants to synchronize the animations with.
@@ -536,10 +539,8 @@
/** The state dispatched from server */
private final InsetsState mLastDispatchedState = new InsetsState();
- // TODO: Use other class to represent the requested visibility of each type, because the
- // display frame and the frame in each source are not used.
/** The requested visibilities sent to server */
- private final InsetsState mRequestedState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
@@ -801,7 +802,7 @@
}
}
- boolean requestedStateStale = false;
+ boolean requestedVisibilityStale = false;
final int[] showTypes = new int[1];
final int[] hideTypes = new int[1];
@@ -822,20 +823,20 @@
final InsetsSourceConsumer consumer = getSourceConsumer(type);
consumer.setControl(control, showTypes, hideTypes);
- if (!requestedStateStale) {
+ if (!requestedVisibilityStale) {
final boolean requestedVisible = consumer.isRequestedVisible();
// We might have changed our requested visibilities while we don't have the control,
// so we need to update our requested state once we have control. Otherwise, our
// requested state at the server side might be incorrect.
final boolean requestedVisibilityChanged =
- requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type);
+ requestedVisible != mRequestedVisibilities.getVisibility(type);
// The IME client visibility will be reset by insets source provider while updating
// control, so if IME is requested visible, we need to send the request to server.
final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible;
- requestedStateStale = requestedVisibilityChanged || imeRequestedVisible;
+ requestedVisibilityStale = requestedVisibilityChanged || imeRequestedVisible;
}
}
@@ -861,7 +862,7 @@
}
// InsetsSourceConsumer#setControl might change the requested visibility.
- updateRequestedVisibility();
+ updateRequestedVisibilities();
}
@Override
@@ -1015,7 +1016,7 @@
if (types == 0) {
// nothing to animate.
listener.onCancelled(null);
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked");
return;
}
@@ -1051,7 +1052,7 @@
}
});
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
return;
}
@@ -1059,7 +1060,7 @@
if (typesReady == 0) {
if (DEBUG) Log.d(TAG, "No types ready. onCancelled()");
listener.onCancelled(null);
- updateRequestedVisibility();
+ updateRequestedVisibilities();
return;
}
@@ -1091,7 +1092,7 @@
} else {
hideDirectly(types, false /* animationFinished */, animationType, fromIme);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
}
/**
@@ -1348,7 +1349,7 @@
/**
* Sends the requested visibilities to window manager if any of them is changed.
*/
- private void updateRequestedVisibility() {
+ private void updateRequestedVisibilities() {
boolean changed = false;
for (int i = mRequestedVisibilityChanged.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mRequestedVisibilityChanged.valueAt(i);
@@ -1357,8 +1358,8 @@
continue;
}
final boolean requestedVisible = consumer.isRequestedVisible();
- if (requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type)) {
- mRequestedState.getSource(type).setVisible(requestedVisible);
+ if (mRequestedVisibilities.getVisibility(type) != requestedVisible) {
+ mRequestedVisibilities.setVisibility(type, requestedVisible);
changed = true;
}
}
@@ -1366,11 +1367,11 @@
if (!changed) {
return;
}
- mHost.onInsetsModified(mRequestedState);
+ mHost.updateRequestedVisibilities(mRequestedVisibilities);
}
- InsetsState getRequestedVisibility() {
- return mRequestedState;
+ InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
@VisibleForTesting
@@ -1425,7 +1426,7 @@
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (fromIme) {
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
@@ -1441,7 +1442,7 @@
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
}
- updateRequestedVisibility();
+ updateRequestedVisibilities();
if (fromIme) {
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 37101b7..f4444a1 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -878,16 +878,5 @@
+ ", mSources= { " + joiner
+ " }";
}
-
- public @NonNull String toSourceVisibilityString() {
- StringJoiner joiner = new StringJoiner(", ");
- for (int i = 0; i < SIZE; i++) {
- InsetsSource source = mSources[i];
- if (source != null) {
- joiner.add(typeToString(i) + ": " + (source.isVisible() ? "visible" : "invisible"));
- }
- }
- return joiner.toString();
- }
}
diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/core/java/android/view/InsetsVisibilities.aidl
similarity index 74%
copy from core/java/com/android/internal/view/InputBindResult.aidl
copy to core/java/android/view/InsetsVisibilities.aidl
index 7ff5c4e..bd573ea 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/core/java/android/view/InsetsVisibilities.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2008 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package android.view;
-parcelable InputBindResult;
+parcelable InsetsVisibilities;
diff --git a/core/java/android/view/InsetsVisibilities.java b/core/java/android/view/InsetsVisibilities.java
new file mode 100644
index 0000000..30668ba
--- /dev/null
+++ b/core/java/android/view/InsetsVisibilities.java
@@ -0,0 +1,130 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.StringJoiner;
+
+/**
+ * A collection of visibilities of insets. This is used for carrying the requested visibilities.
+ * @hide
+ */
+public class InsetsVisibilities implements Parcelable {
+
+ private static final int UNSPECIFIED = 0;
+ private static final int VISIBLE = 1;
+ private static final int INVISIBLE = -1;
+
+ private final int[] mVisibilities = new int[InsetsState.SIZE];
+
+ public InsetsVisibilities() {
+ }
+
+ public InsetsVisibilities(InsetsVisibilities other) {
+ set(other);
+ }
+
+ public InsetsVisibilities(Parcel in) {
+ in.readIntArray(mVisibilities);
+ }
+
+ /**
+ * Copies from another {@link InsetsVisibilities}.
+ *
+ * @param other an instance of {@link InsetsVisibilities}.
+ */
+ public void set(InsetsVisibilities other) {
+ System.arraycopy(other.mVisibilities, InsetsState.FIRST_TYPE, mVisibilities,
+ InsetsState.FIRST_TYPE, InsetsState.SIZE);
+ }
+
+ /**
+ * Sets a visibility to a type.
+ *
+ * @param type The {@link @InsetsState.InternalInsetsType}.
+ * @param visible {@code true} represents visible; {@code false} represents invisible.
+ */
+ public void setVisibility(@InsetsState.InternalInsetsType int type, boolean visible) {
+ mVisibilities[type] = visible ? VISIBLE : INVISIBLE;
+ }
+
+ /**
+ * Returns the specified insets visibility of the type. If it has never been specified,
+ * this returns the default visibility.
+ *
+ * @param type The {@link @InsetsState.InternalInsetsType}.
+ * @return The specified visibility or the default one if it is not specified.
+ */
+ public boolean getVisibility(@InsetsState.InternalInsetsType int type) {
+ final int visibility = mVisibilities[type];
+ return visibility == UNSPECIFIED
+ ? InsetsState.getDefaultVisibility(type)
+ : visibility == VISIBLE;
+ }
+
+ @Override
+ public String toString() {
+ StringJoiner joiner = new StringJoiner(", ");
+ for (int type = InsetsState.FIRST_TYPE; type <= InsetsState.LAST_TYPE; type++) {
+ final int visibility = mVisibilities[type];
+ if (visibility != UNSPECIFIED) {
+ joiner.add(InsetsState.typeToString(type) + ": "
+ + (visibility == VISIBLE ? "visible" : "invisible"));
+ }
+ }
+ return joiner.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mVisibilities);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof InsetsVisibilities)) {
+ return false;
+ }
+ return Arrays.equals(mVisibilities, ((InsetsVisibilities) other).mVisibilities);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeIntArray(mVisibilities);
+ }
+
+ public static final @NonNull Creator<InsetsVisibilities> CREATOR =
+ new Creator<InsetsVisibilities>() {
+
+ public InsetsVisibilities createFromParcel(Parcel in) {
+ return new InsetsVisibilities(in);
+ }
+
+ public InsetsVisibilities[] newArray(int size) {
+ return new InsetsVisibilities[size];
+ }
+ };
+}
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index cdc099b..bd68401 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -197,6 +197,12 @@
public ActivityManager.RunningTaskInfo taskInfo;
/**
+ * {@code true} if picture-in-picture permission is granted in {@link android.app.AppOpsManager}
+ */
+ @UnsupportedAppUsage
+ public boolean allowEnterPip;
+
+ /**
* The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
* for non-app window.
*/
@@ -206,10 +212,11 @@
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
Rect localBounds, Rect screenSpaceBounds,
WindowConfiguration windowConfig, boolean isNotInRecents,
- SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo) {
+ SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo,
+ boolean allowEnterPip) {
this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
- startBounds, taskInfo, INVALID_WINDOW_TYPE);
+ startBounds, taskInfo, allowEnterPip, INVALID_WINDOW_TYPE);
}
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
@@ -217,7 +224,7 @@
Rect localBounds, Rect screenSpaceBounds,
WindowConfiguration windowConfig, boolean isNotInRecents,
SurfaceControl startLeash, Rect startBounds,
- ActivityManager.RunningTaskInfo taskInfo,
+ ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip,
@WindowManager.LayoutParams.WindowType int windowType) {
this.mode = mode;
this.taskId = taskId;
@@ -235,6 +242,7 @@
this.startLeash = startLeash;
this.startBounds = startBounds == null ? null : new Rect(startBounds);
this.taskInfo = taskInfo;
+ this.allowEnterPip = allowEnterPip;
this.windowType = windowType;
}
@@ -255,6 +263,7 @@
startLeash = in.readTypedObject(SurfaceControl.CREATOR);
startBounds = in.readTypedObject(Rect.CREATOR);
taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ allowEnterPip = in.readBoolean();
windowType = in.readInt();
}
@@ -281,6 +290,7 @@
dest.writeTypedObject(startLeash, 0 /* flags */);
dest.writeTypedObject(startBounds, 0 /* flags */);
dest.writeTypedObject(taskInfo, 0 /* flags */);
+ dest.writeBoolean(allowEnterPip);
dest.writeInt(windowType);
}
@@ -299,6 +309,7 @@
pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
pw.print(prefix); pw.print("leash="); pw.println(leash);
pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo);
+ pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ff2d2eb..aaf53ee 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -29,6 +29,7 @@
import android.graphics.ColorSpace;
import android.graphics.HardwareRenderer;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
@@ -408,6 +409,20 @@
}
/**
+ * Returns the default size of this Surface provided by the consumer of the surface.
+ * Should only be used by the producer of the surface.
+ *
+ * @hide
+ */
+ @NonNull
+ public Point getDefaultSize() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject));
+ }
+ }
+
+ /**
* Gets a {@link Canvas} for drawing into this surface.
*
* After drawing into the provided {@link Canvas}, the caller must
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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b9346b5..5bd3aef 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -304,7 +304,7 @@
* {@hide}
*/
public static final boolean INSETS_LAYOUT_GENERALIZATION =
- SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, false);
+ SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, true);
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
@@ -1135,7 +1135,7 @@
controlInsetsForCompatibility(mWindowAttributes);
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
- mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
+ mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
if (mTranslator != null) {
mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
@@ -2519,6 +2519,14 @@
|| lp.type == TYPE_VOLUME_OVERLAY;
}
+ private Rect getWindowBoundsInsetSystemBars() {
+ final Rect bounds = new Rect(
+ mContext.getResources().getConfiguration().windowConfiguration.getBounds());
+ bounds.inset(mInsetsController.getState().calculateInsets(
+ bounds, Type.systemBars(), false /* ignoreVisibility */));
+ return bounds;
+ }
+
int dipToPx(int dip) {
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
return (int) (displayMetrics.density * dip + 0.5f);
@@ -2605,8 +2613,9 @@
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
// For wrap content, we have to remeasure later on anyways. Use size consistent with
// below so we get best use of the measure cache.
- desiredWindowWidth = dipToPx(config.screenWidthDp);
- desiredWindowHeight = dipToPx(config.screenHeightDp);
+ final Rect bounds = getWindowBoundsInsetSystemBars();
+ desiredWindowWidth = bounds.width();
+ desiredWindowHeight = bounds.height();
} else {
// After addToDisplay, the frame contains the frameHint from window manager, which
// for most windows is going to be the same size as the result of relayoutWindow.
@@ -2683,9 +2692,9 @@
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
- Configuration config = res.getConfiguration();
- desiredWindowWidth = dipToPx(config.screenWidthDp);
- desiredWindowHeight = dipToPx(config.screenHeightDp);
+ final Rect bounds = getWindowBoundsInsetSystemBars();
+ desiredWindowWidth = bounds.width();
+ desiredWindowHeight = bounds.height();
}
}
}
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index ce882da..efffa2b 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -149,10 +149,10 @@
}
@Override
- public void onInsetsModified(InsetsState insetsState) {
+ public void updateRequestedVisibilities(InsetsVisibilities vis) {
try {
if (mViewRoot.mAdded) {
- mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState);
+ mViewRoot.mWindowSession.updateRequestedVisibilities(mViewRoot.mWindow, vis);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to call insetsModified", e);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fcfb0ab..eb410ab 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -400,6 +400,11 @@
*/
int TRANSIT_PIP = 10;
/**
+ * The screen is turning on.
+ * @hide
+ */
+ int TRANSIT_WAKE = 11;
+ /**
* The first slot for custom transition types. Callers (like Shell) can make use of custom
* transition types for dealing with special cases. These types are effectively ignored by
* Core and will just be passed along as part of TransitionInfo objects. An example is
@@ -408,7 +413,7 @@
* implementation.
* @hide
*/
- int TRANSIT_FIRST_CUSTOM = 11;
+ int TRANSIT_FIRST_CUSTOM = 12;
/**
* @hide
@@ -425,6 +430,7 @@
TRANSIT_KEYGUARD_OCCLUDE,
TRANSIT_KEYGUARD_UNOCCLUDE,
TRANSIT_PIP,
+ TRANSIT_WAKE,
TRANSIT_FIRST_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
@@ -937,6 +943,8 @@
case TRANSIT_KEYGUARD_GOING_AWAY: return "KEYGUARD_GOING_AWAY";
case TRANSIT_KEYGUARD_OCCLUDE: return "KEYGUARD_OCCLUDE";
case TRANSIT_KEYGUARD_UNOCCLUDE: return "KEYGUARD_UNOCCLUDE";
+ case TRANSIT_PIP: return "PIP";
+ case TRANSIT_WAKE: return "WAKE";
case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM";
default:
if (type > TRANSIT_FIRST_CUSTOM) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index ae54f51..c413a9b 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -135,7 +135,7 @@
*/
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
@@ -181,10 +181,10 @@
*/
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
- return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibility,
+ return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibilities,
outInputChannel, outInsetsState, outActiveControls);
}
@@ -454,7 +454,7 @@
}
@Override
- public void insetsModified(android.view.IWindow window, android.view.InsetsState state) {
+ public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) {
}
@Override
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/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 38019c9..5f036a3 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1013,8 +1013,10 @@
*
* @param imeConsumesInput {@code true} when the IME is consuming input and the cursor should be
* hidden, {@code false} when input to the editor resumes and the cursor should be shown again.
- * @return {@code true} on success, {@code false} if the input connection is no longer valid, or
- * the protocol is not supported.
+ * @return For editor authors, the return value will always be ignored. For IME authors, this
+ * method returns {@code true} if the request was sent (whether or not the associated
+ * editor does something based on this request), {@code false} if the input connection
+ * is no longer valid.
*/
default boolean setImeConsumesInput(boolean imeConsumesInput) {
return false;
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 9b463bb..96198c6 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -418,8 +418,9 @@
}
/**
- * Return a unique ID for this input method. The ID is generated from
- * the package and class name implementing the method.
+ * @return a unique ID for this input method, which is guaranteed to be the same as the result
+ * of {@code getComponent().flattenToShortString()}.
+ * @see ComponentName#unflattenFromString(String)
*/
public String getId() {
return mId;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8e0d9bc..c46b77f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -87,6 +87,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -95,11 +96,9 @@
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;
-import com.android.internal.view.InputBindResult;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -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,6 @@
}
}
- /** @hide */
- @UnsupportedAppUsage
- public IInputMethodClient getClient() {
- return mClient;
- }
-
- /** @hide */
- @UnsupportedAppUsage
- public IInputContext getInputContext() {
- return mIInputContext;
- }
-
/**
* Returns the list of installed input methods.
*
@@ -1397,8 +1381,8 @@
public boolean isAcceptingText() {
checkFocus();
synchronized (mH) {
- return mServedInputConnectionWrapper != null
- && mServedInputConnectionWrapper.getInputConnection() != null;
+ return mServedInputConnection != null
+ && mServedInputConnection.getInputConnection() != null;
}
}
@@ -1452,9 +1436,9 @@
*/
void clearConnectionLocked() {
mCurrentTextBoxAttribute = null;
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.deactivate();
- mServedInputConnectionWrapper = null;
+ if (mServedInputConnection != null) {
+ mServedInputConnection.deactivate();
+ mServedInputConnection = null;
}
}
@@ -1950,11 +1934,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 +1955,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 +1972,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 +3067,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 +3088,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 +3214,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/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index ae927cf..e31eabb 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -114,6 +115,7 @@
* @throws ServiceNotFoundException When {@link TextServicesManager} is not available.
* @hide
*/
+ @UserHandleAware
@NonNull
public static TextServicesManager createInstance(@NonNull Context context)
throws ServiceNotFoundException {
@@ -178,6 +180,7 @@
* languages in settings will be returned.
* @return a spell checker session of the spell checker
*/
+ @UserHandleAware
@Nullable
public SpellCheckerSession newSpellCheckerSession(@Nullable Bundle bundle,
@Nullable Locale locale,
@@ -208,6 +211,7 @@
* @param listener a spell checker session lister for getting results from the spell checker.
* @return The spell checker session of the spell checker.
*/
+ @UserHandleAware
@Nullable
public SpellCheckerSession newSpellCheckerSession(
@NonNull SpellCheckerSessionParams params,
@@ -283,6 +287,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
publicAlternatives = "Use {@link #getEnabledSpellCheckerInfos()} instead.")
+ @UserHandleAware
public SpellCheckerInfo[] getEnabledSpellCheckers() {
try {
final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId);
@@ -300,6 +305,7 @@
*
* @return The list of currently enabled spell checkers.
*/
+ @UserHandleAware
@NonNull
public List<SpellCheckerInfo> getEnabledSpellCheckerInfos() {
final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers();
@@ -312,6 +318,7 @@
*
* @return The current active spell checker info.
*/
+ @UserHandleAware
@Nullable
public SpellCheckerInfo getCurrentSpellCheckerInfo() {
try {
@@ -328,6 +335,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@link #getCurrentSpellCheckerInfo()} instead.")
+ @UserHandleAware
@Nullable
public SpellCheckerInfo getCurrentSpellChecker() {
return getCurrentSpellCheckerInfo();
@@ -343,6 +351,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @UserHandleAware
@Nullable
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
boolean allowImplicitlySelectedSubtype) {
@@ -358,6 +367,7 @@
*
* @return {@code true} if spell checker is enabled, {@code false} otherwise.
*/
+ @UserHandleAware
public boolean isSpellCheckerEnabled() {
try {
return mService.isSpellCheckerEnabled(mUserId);
@@ -366,6 +376,7 @@
}
}
+ @UserHandleAware
void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
try {
mService.finishSpellCheckerService(mUserId, listener);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 721260e..87f4a15 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5938,36 +5938,37 @@
boolean handled = false;
boolean okToSend = true;
switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_NUMPAD_ENTER:
- okToSend = false;
- break;
- case KeyEvent.KEYCODE_BACK:
- if (mFiltered && mPopup != null && mPopup.isShowing()) {
- if (event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0) {
- KeyEvent.DispatcherState state = getKeyDispatcherState();
- if (state != null) {
- state.startTracking(event, this);
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_NUMPAD_ENTER:
+ okToSend = false;
+ break;
+ case KeyEvent.KEYCODE_BACK:
+ case KeyEvent.KEYCODE_ESCAPE:
+ if (mFiltered && mPopup != null && mPopup.isShowing()) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
+ handled = true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP
+ && event.isTracking() && !event.isCanceled()) {
+ handled = true;
+ mTextFilter.setText("");
}
- handled = true;
- } else if (event.getAction() == KeyEvent.ACTION_UP
- && event.isTracking() && !event.isCanceled()) {
- handled = true;
- mTextFilter.setText("");
}
- }
- okToSend = false;
- break;
- case KeyEvent.KEYCODE_SPACE:
- // Only send spaces once we are filtered
- okToSend = mFiltered;
- break;
+ okToSend = false;
+ break;
+ case KeyEvent.KEYCODE_SPACE:
+ // Only send spaces once we are filtered
+ okToSend = mFiltered;
+ break;
}
if (okToSend) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ce29eea..cfae95d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -788,8 +788,8 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()
- && !mPopup.isDropDownAlwaysVisible()) {
+ if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
+ && isPopupShowing() && !mPopup.isDropDownAlwaysVisible()) {
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 6232480..7766f1a 100755
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1071,7 +1071,8 @@
* @see #setModal(boolean)
*/
public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
+ if ((keyCode == KeyEvent.KEYCODE_BACK
+ || keyCode == KeyEvent.KEYCODE_ESCAPE) && isShowing()) {
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
final View anchorView = mDropDownAnchorView;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index e7e148a..decd9a5 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -2521,7 +2521,8 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ || event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) {
if (getKeyDispatcherState() == null) {
return super.dispatchKeyEvent(event);
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e827f0a..91fc5a5 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5824,6 +5824,25 @@
return false;
}
+ /** @hide */
+ public void updateAppInfo(@NonNull ApplicationInfo info) {
+ if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) {
+ // Overlay paths are generated against a particular version of an application.
+ // The overlays paths of a newly upgraded application are incompatible with the
+ // old version of the application.
+ mApplication = info;
+ }
+ if (hasSizedRemoteViews()) {
+ for (RemoteViews layout : mSizedRemoteViews) {
+ layout.updateAppInfo(info);
+ }
+ }
+ if (hasLandscapeAndPortraitLayouts()) {
+ mLandscape.updateAppInfo(info);
+ mPortrait.updateAppInfo(info);
+ }
+ }
+
private Context getContextForResources(Context context) {
if (mApplication != null) {
if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 693b13b..3ad7b46 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -509,7 +509,8 @@
mTempRect.setEmpty();
if (!canScroll()) {
- if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
+ if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK
+ && event.getKeyCode() != KeyEvent.KEYCODE_ESCAPE) {
View currentFocused = findFocus();
if (currentFocused == this) currentFocused = null;
View nextFocused = FocusFinder.getInstance().findNextFocus(this,
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 1efd2e3..acf20d7 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -89,11 +89,11 @@
private boolean mNotCopyable;
private boolean mIsCopied;
private int mInitBackgroundColor;
- private int mInitIconBackgroundColor;
private View mIconView;
private Bitmap mParceledIconBitmap;
private View mBrandingImageView;
private Bitmap mParceledBrandingBitmap;
+ private Bitmap mParceledIconBackgroundBitmap;
private Duration mIconAnimationDuration;
private Instant mIconAnimationStart;
@@ -130,11 +130,12 @@
private final Context mContext;
private int mIconSize;
private @ColorInt int mBackgroundColor;
- private @ColorInt int mIconBackground;
private Bitmap mParceledIconBitmap;
+ private Bitmap mParceledIconBackgroundBitmap;
private Drawable mIconDrawable;
// It is only set for legacy splash screen which won't be sent across processes.
private Drawable mOverlayDrawable;
+ private Drawable mIconBackground;
private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
private RemoteCallback mClientCallback;
private int mBrandingImageWidth;
@@ -155,7 +156,6 @@
public Builder createFromParcel(SplashScreenViewParcelable parcelable) {
mIconSize = parcelable.getIconSize();
mBackgroundColor = parcelable.getBackgroundColor();
- mIconBackground = parcelable.getIconBackground();
mSurfacePackage = parcelable.mSurfacePackage;
if (mSurfacePackage == null && parcelable.mIconBitmap != null) {
// We only create a Bitmap copies of immobile icons since animated icon are using
@@ -163,6 +163,11 @@
mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
mParceledIconBitmap = parcelable.mIconBitmap;
}
+ if (parcelable.mIconBackground != null) {
+ mIconBackground = new BitmapDrawable(mContext.getResources(),
+ parcelable.mIconBackground);
+ mParceledIconBackgroundBitmap = parcelable.mIconBackground;
+ }
if (parcelable.mBrandingBitmap != null) {
setBrandingDrawable(new BitmapDrawable(mContext.getResources(),
parcelable.mBrandingBitmap), parcelable.mBrandingWidth,
@@ -213,8 +218,8 @@
/**
* Set the background color for the icon.
*/
- public Builder setIconBackground(int color) {
- mIconBackground = color;
+ public Builder setIconBackground(Drawable iconBackground) {
+ mIconBackground = iconBackground;
return this;
}
@@ -245,7 +250,6 @@
final SplashScreenView view = (SplashScreenView)
layoutInflater.inflate(R.layout.splash_screen_view, null, false);
view.mInitBackgroundColor = mBackgroundColor;
- view.mInitIconBackgroundColor = mIconBackground;
if (mOverlayDrawable != null) {
view.setBackground(mOverlayDrawable);
} else {
@@ -263,25 +267,29 @@
mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
view.mIconAnimationStart = mIconAnimationStart;
view.mIconAnimationDuration = mIconAnimationDuration;
- } else {
- view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
- if (mIconSize != 0) {
- final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
- params.width = mIconSize;
- params.height = mIconSize;
- view.mIconView.setLayoutParams(params);
- if (mIconDrawable != null) {
- view.mIconView.setBackground(mIconDrawable);
- }
+ } else if (mIconSize != 0) {
+ ImageView imageView = view.findViewById(R.id.splashscreen_icon_view);
+ assert imageView != null;
+
+ final ViewGroup.LayoutParams params = imageView.getLayoutParams();
+ params.width = mIconSize;
+ params.height = mIconSize;
+ imageView.setLayoutParams(params);
+ if (mIconDrawable != null) {
+ imageView.setImageDrawable(mIconDrawable);
}
+ if (mIconBackground != null) {
+ imageView.setBackground(mIconBackground);
+ }
+ view.mIconView = imageView;
}
if (mOverlayDrawable != null || mIconDrawable == null) {
view.setNotCopyable();
}
- if (mParceledIconBitmap != null) {
- view.mParceledIconBitmap = mParceledIconBitmap;
- }
+ view.mParceledIconBackgroundBitmap = mParceledIconBackgroundBitmap;
+ view.mParceledIconBitmap = mParceledIconBitmap;
+
// branding image
if (mBrandingImageHeight > 0 && mBrandingImageWidth > 0 && mBrandingDrawable != null) {
final ViewGroup.LayoutParams params = view.mBrandingImageView.getLayoutParams();
@@ -310,6 +318,7 @@
private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
final SurfaceView surfaceView = new SurfaceView(view.getContext());
surfaceView.setPadding(0, 0, 0, 0);
+ surfaceView.setBackground(mIconBackground);
if (mSurfacePackage == null) {
if (DEBUG) {
Log.d(TAG,
@@ -475,7 +484,11 @@
}
setVisibility(GONE);
if (mParceledIconBitmap != null) {
- mIconView.setBackground(null);
+ if (mIconView instanceof ImageView) {
+ ((ImageView) mIconView).setImageDrawable(null);
+ } else if (mIconView != null) {
+ mIconView.setBackground(null);
+ }
mParceledIconBitmap.recycle();
mParceledIconBitmap = null;
}
@@ -484,6 +497,13 @@
mParceledBrandingBitmap.recycle();
mParceledBrandingBitmap = null;
}
+ if (mParceledIconBackgroundBitmap != null) {
+ if (mIconView != null) {
+ mIconView.setBackground(null);
+ }
+ mParceledIconBackgroundBitmap.recycle();
+ mParceledIconBackgroundBitmap = null;
+ }
if (mWindow != null) {
final DecorView decorView = (DecorView) mWindow.peekDecorView();
if (DEBUG) {
@@ -600,15 +620,6 @@
}
/**
- * Get the icon background color
- * @hide
- */
- @TestApi
- public @ColorInt int getIconBackgroundColor() {
- return mInitIconBackgroundColor;
- }
-
- /**
* Get the initial background color of this view.
* @hide
*/
@@ -637,7 +648,7 @@
public static class SplashScreenViewParcelable implements Parcelable {
private int mIconSize;
private int mBackgroundColor;
- private int mIconBackground;
+ private Bitmap mIconBackground;
private Bitmap mIconBitmap = null;
private int mBrandingWidth;
@@ -653,11 +664,11 @@
public SplashScreenViewParcelable(SplashScreenView view) {
mIconSize = view.mIconView.getWidth();
mBackgroundColor = view.getInitBackgroundColor();
- mIconBackground = view.getIconBackgroundColor();
+ mIconBackground = copyDrawable(view.getIconView().getBackground());
mSurfacePackage = view.mSurfacePackageCopy;
if (mSurfacePackage == null) {
// We only need to copy the drawable if we are not using a SurfaceView
- mIconBitmap = copyDrawable(view.getIconView().getBackground());
+ mIconBitmap = copyDrawable(((ImageView) view.getIconView()).getDrawable());
}
mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
@@ -703,7 +714,7 @@
mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
mIconAnimationStartMillis = source.readLong();
mIconAnimationDurationMillis = source.readLong();
- mIconBackground = source.readInt();
+ mIconBackground = source.readTypedObject(Bitmap.CREATOR);
mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
mClientCallback = source.readTypedObject(RemoteCallback.CREATOR);
}
@@ -723,7 +734,7 @@
dest.writeTypedObject(mBrandingBitmap, flags);
dest.writeLong(mIconAnimationStartMillis);
dest.writeLong(mIconAnimationDurationMillis);
- dest.writeInt(mIconBackground);
+ dest.writeTypedObject(mIconBackground, flags);
dest.writeTypedObject(mSurfacePackage, flags);
dest.writeTypedObject(mClientCallback, flags);
}
@@ -760,10 +771,6 @@
return mBackgroundColor;
}
- int getIconBackground() {
- return mIconBackground;
- }
-
/**
* Sets the {@link RemoteCallback} that will be called by the client to notify the shell
* of the removal of the {@link SplashScreenView}.
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/TaskFragmentAppearedInfo.java b/core/java/android/window/TaskFragmentAppearedInfo.java
index 234b30c..89d9a95 100644
--- a/core/java/android/window/TaskFragmentAppearedInfo.java
+++ b/core/java/android/window/TaskFragmentAppearedInfo.java
@@ -17,6 +17,7 @@
package android.window;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.SurfaceControl;
@@ -25,6 +26,7 @@
* Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
* @hide
*/
+@TestApi
public final class TaskFragmentAppearedInfo implements Parcelable {
@NonNull
@@ -33,16 +35,19 @@
@NonNull
private final SurfaceControl mLeash;
+ /** @hide */
public TaskFragmentAppearedInfo(
@NonNull TaskFragmentInfo taskFragmentInfo, @NonNull SurfaceControl leash) {
mTaskFragmentInfo = taskFragmentInfo;
mLeash = leash;
}
+ @NonNull
public TaskFragmentInfo getTaskFragmentInfo() {
return mTaskFragmentInfo;
}
+ @NonNull
public SurfaceControl getLeash() {
return mLeash;
}
@@ -52,6 +57,7 @@
mLeash = in.readTypedObject(SurfaceControl.CREATOR);
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mTaskFragmentInfo, flags);
@@ -79,6 +85,7 @@
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
index e4d6a6c..81ab783 100644
--- a/core/java/android/window/TaskFragmentCreationParams.java
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.WindowingMode;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
@@ -29,11 +30,12 @@
* Data object for options to create TaskFragment with.
* @hide
*/
+@TestApi
public final class TaskFragmentCreationParams implements Parcelable {
/** The organizer that will organize this TaskFragment. */
@NonNull
- private final ITaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentOrganizerToken mOrganizer;
/**
* Unique token assigned from the client organizer to identify the {@link TaskFragmentInfo} when
@@ -58,25 +60,29 @@
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
private TaskFragmentCreationParams(
- @NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
- @NonNull IBinder ownerToken) {
+ @NonNull TaskFragmentOrganizerToken organizer,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
mFragmentToken = fragmentToken;
mOwnerToken = ownerToken;
}
- public ITaskFragmentOrganizer getOrganizer() {
+ @NonNull
+ public TaskFragmentOrganizerToken getOrganizer() {
return mOrganizer;
}
+ @NonNull
public IBinder getFragmentToken() {
return mFragmentToken;
}
+ @NonNull
public IBinder getOwnerToken() {
return mOwnerToken;
}
+ @NonNull
public Rect getInitialBounds() {
return mInitialBounds;
}
@@ -87,16 +93,17 @@
}
private TaskFragmentCreationParams(Parcel in) {
- mOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
+ mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
mFragmentToken = in.readStrongBinder();
mOwnerToken = in.readStrongBinder();
mInitialBounds.readFromParcel(in);
mWindowingMode = in.readInt();
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStrongInterface(mOrganizer);
+ mOrganizer.writeToParcel(dest, flags);
dest.writeStrongBinder(mFragmentToken);
dest.writeStrongBinder(mOwnerToken);
mInitialBounds.writeToParcel(dest, flags);
@@ -128,16 +135,17 @@
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
/** Builder to construct the options to create TaskFragment with. */
- public static class Builder {
+ public static final class Builder {
@NonNull
- private final ITaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentOrganizerToken mOrganizer;
@NonNull
private final IBinder mFragmentToken;
@@ -151,26 +159,29 @@
@WindowingMode
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
- public Builder(@NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
- @NonNull IBinder ownerToken) {
+ public Builder(@NonNull TaskFragmentOrganizerToken organizer,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
mFragmentToken = fragmentToken;
mOwnerToken = ownerToken;
}
/** Sets the initial bounds for the TaskFragment. */
+ @NonNull
public Builder setInitialBounds(@NonNull Rect bounds) {
mInitialBounds.set(bounds);
return this;
}
/** Sets the initial windowing mode for the TaskFragment. */
+ @NonNull
public Builder setWindowingMode(@WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
/** Constructs the options to create TaskFragment with. */
+ @NonNull
public TaskFragmentCreationParams build() {
final TaskFragmentCreationParams result = new TaskFragmentCreationParams(
mOrganizer, mFragmentToken, mOwnerToken);
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index 45975db..dac420b 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.IBinder;
@@ -35,11 +36,12 @@
* Stores information about a particular TaskFragment.
* @hide
*/
+@TestApi
public final class TaskFragmentInfo implements Parcelable {
/**
- * Client assigned unique token in {@link TaskFragmentCreationParams#mFragmentToken} to create
- * this TaskFragment with.
+ * Client assigned unique token in {@link TaskFragmentCreationParams#getFragmentToken()} to
+ * create this TaskFragment with.
*/
@NonNull
private final IBinder mFragmentToken;
@@ -50,9 +52,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;
@@ -60,32 +65,38 @@
* List of Activity tokens that are children of this TaskFragment. It only contains Activities
* that belong to the organizer process for security.
*/
+ @NonNull
private final List<IBinder> mActivities = new ArrayList<>();
/** Relative position of the fragment's top left corner in the parent container. */
private final Point mPositionInParent;
+ /** @hide */
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
- @NonNull Configuration configuration, boolean isEmpty, boolean isVisible,
- List<IBinder> activities, @NonNull Point positionInParent) {
+ @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);
}
+ @NonNull
public IBinder getFragmentToken() {
return mFragmentToken;
}
+ @NonNull
public WindowContainerToken getToken() {
return mToken;
}
+ @NonNull
public Configuration getConfiguration() {
return mConfiguration;
}
@@ -94,10 +105,15 @@
return mIsEmpty;
}
+ public boolean hasRunningActivity() {
+ return mHasRunningActivity;
+ }
+
public boolean isVisible() {
return mIsVisible;
}
+ @NonNull
public List<IBinder> getActivities() {
return mActivities;
}
@@ -125,6 +141,7 @@
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)
@@ -136,17 +153,20 @@
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));
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStrongBinder(mFragmentToken);
dest.writeTypedObject(mToken, flags);
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
+ dest.writeBoolean(mHasRunningActivity);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
dest.writeTypedObject(mPositionInParent, flags);
@@ -172,11 +192,13 @@
+ " fragmentToken=" + mFragmentToken
+ " token=" + mToken
+ " isEmpty=" + mIsEmpty
+ + " hasRunningActivity=" + mHasRunningActivity
+ " isVisible=" + mIsVisible
+ " positionInParent=" + mPositionInParent
+ "}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index b252df7..f22f0b2 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -18,6 +18,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -26,9 +27,10 @@
import java.util.concurrent.Executor;
/**
- * Interface for WindowManager to delegate control of {@link com.android.server.wm.TaskFragment}.
+ * Interface for WindowManager to delegate control of {@code TaskFragment}.
* @hide
*/
+@TestApi
public class TaskFragmentOrganizer extends WindowOrganizer {
/**
@@ -39,6 +41,7 @@
/**
* Creates a {@link Bundle} with an exception that can be passed to
* {@link ITaskFragmentOrganizer#onTaskFragmentError}.
+ * @hide
*/
public static Bundle putExceptionInBundle(@NonNull Throwable exception) {
final Bundle exceptionBundle = new Bundle();
@@ -126,6 +129,8 @@
super.applyTransaction(t);
}
+ // Suppress the lint because it is not a registration method.
+ @SuppressWarnings("ExecutorRegistration")
@Override
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
@NonNull WindowContainerTransactionCallback callback) {
@@ -169,8 +174,11 @@
}
};
- public ITaskFragmentOrganizer getIOrganizer() {
- return mInterface;
+ private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface);
+
+ @NonNull
+ public TaskFragmentOrganizerToken getOrganizerToken() {
+ return mToken;
}
private ITaskFragmentOrganizerController getController() {
diff --git a/core/java/android/window/TaskFragmentOrganizerToken.java b/core/java/android/window/TaskFragmentOrganizerToken.java
new file mode 100644
index 0000000..d5216a6
--- /dev/null
+++ b/core/java/android/window/TaskFragmentOrganizerToken.java
@@ -0,0 +1,97 @@
+/*
+ * 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Interface to communicate between window manager and {@link TaskFragmentOrganizer}.
+ * <p>
+ * Window manager will dispatch TaskFragment information updates via this interface.
+ * It is necessary because {@link ITaskFragmentOrganizer} aidl interface can not be used as a
+ * {@link TestApi}.
+ * @hide
+ */
+@TestApi
+public final class TaskFragmentOrganizerToken implements Parcelable {
+ private final ITaskFragmentOrganizer mRealToken;
+
+ TaskFragmentOrganizerToken(ITaskFragmentOrganizer realToken) {
+ mRealToken = realToken;
+ }
+
+ /** @hide */
+ public IBinder asBinder() {
+ return mRealToken.asBinder();
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongInterface(mRealToken);
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<TaskFragmentOrganizerToken> CREATOR =
+ new Creator<TaskFragmentOrganizerToken>() {
+ @Override
+ public TaskFragmentOrganizerToken createFromParcel(Parcel in) {
+ final ITaskFragmentOrganizer realToken =
+ ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
+ // The TaskFragmentOrganizerToken may be null for TaskOrganizer or
+ // DisplayAreaOrganizer.
+ if (realToken == null) {
+ return null;
+ }
+ return new TaskFragmentOrganizerToken(realToken);
+ }
+
+ @Override
+ public TaskFragmentOrganizerToken[] newArray(int size) {
+ return new TaskFragmentOrganizerToken[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return mRealToken.asBinder().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "TaskFragmentOrganizerToken{" + mRealToken + "}";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof TaskFragmentOrganizerToken)) {
+ return false;
+ }
+ return mRealToken.asBinder() == ((TaskFragmentOrganizerToken) obj).asBinder();
+ }
+}
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 6351b03..34facc4 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -17,13 +17,17 @@
package android.window;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.WindowManager.TransitionType;
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;
+import android.view.WindowManager;
/**
* A parcelable filter that can be used for rerouting transitions to a remote. This is a local
@@ -50,7 +54,10 @@
* When non-null: this is a list of transition types that this filter applies to. This filter
* will fail for transitions that aren't one of these types.
*/
- @Nullable public int[] mTypeSet = null;
+ @Nullable public @TransitionType int[] mTypeSet = null;
+
+ /** All flags must be set on a transition. */
+ public @WindowManager.TransitionFlags int mFlags = 0;
/**
* A list of required changes. To pass, a transition must meet all requirements.
@@ -62,6 +69,7 @@
private TransitionFilter(Parcel in) {
mTypeSet = in.createIntArray();
+ mFlags = in.readInt();
mRequirements = in.createTypedArray(Requirement.CREATOR);
}
@@ -78,10 +86,16 @@
}
if (!typePass) return false;
}
+ if ((info.getFlags() & mFlags) != mFlags) {
+ return false;
+ }
// Make sure info meets all of the requirements.
if (mRequirements != null) {
for (int i = 0; i < mRequirements.length; ++i) {
- if (!mRequirements[i].matches(info)) return false;
+ final boolean matches = mRequirements[i].matches(info);
+ if (matches == mRequirements[i].mNot) {
+ return false;
+ }
}
}
return true;
@@ -91,6 +105,7 @@
/** @hide */
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeIntArray(mTypeSet);
+ dest.writeInt(mFlags);
dest.writeTypedArray(mRequirements, flags);
}
@@ -120,10 +135,11 @@
sb.append("{types=[");
if (mTypeSet != null) {
for (int i = 0; i < mTypeSet.length; ++i) {
- sb.append((i == 0 ? "" : ",") + mTypeSet[i]);
+ sb.append((i == 0 ? "" : ",") + WindowManager.transitTypeToString(mTypeSet[i]));
}
}
- sb.append("] checks=[");
+ sb.append("] flags=0x" + Integer.toHexString(mFlags));
+ sb.append(" checks=[");
if (mRequirements != null) {
for (int i = 0; i < mRequirements.length; ++i) {
sb.append((i == 0 ? "" : ",") + mRequirements[i]);
@@ -138,23 +154,43 @@
*/
public static final class Requirement implements Parcelable {
public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
+
+ /** This only matches if the change is independent of its parents. */
+ public boolean mMustBeIndependent = true;
+
+ /** If this matches, the parent filter will fail */
+ public boolean mNot = false;
+
public int[] mModes = null;
+
+ /** Matches only if all the flags here are set on the change. */
+ public @TransitionInfo.ChangeFlags int mFlags = 0;
+
+ /** If this needs to be a task. */
+ public boolean mMustBeTask = false;
+
public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
+ public ComponentName mTopActivity;
public Requirement() {
}
private Requirement(Parcel in) {
mActivityType = in.readInt();
+ mMustBeIndependent = in.readBoolean();
+ mNot = in.readBoolean();
mModes = in.createIntArray();
+ mFlags = in.readInt();
+ mMustBeTask = in.readBoolean();
mOrder = in.readInt();
+ mTopActivity = in.readTypedObject(ComponentName.CREATOR);
}
/** Go through changes and find if at-least one change matches this filter */
boolean matches(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (!TransitionInfo.isIndependent(change, info)) {
+ if (mMustBeIndependent && !TransitionInfo.isIndependent(change, info)) {
// Only look at independent animating windows.
continue;
}
@@ -167,6 +203,7 @@
continue;
}
}
+ if (!matchesTopActivity(change.getTaskInfo())) continue;
if (mModes != null) {
boolean pass = false;
for (int m = 0; m < mModes.length; ++m) {
@@ -177,25 +214,44 @@
}
if (!pass) continue;
}
+ if ((change.getFlags() & mFlags) != mFlags) {
+ continue;
+ }
+ if (mMustBeTask && change.getTaskInfo() == null) {
+ continue;
+ }
return true;
}
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
/** @hide */
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mActivityType);
+ dest.writeBoolean(mMustBeIndependent);
+ dest.writeBoolean(mNot);
dest.writeIntArray(mModes);
+ dest.writeInt(mFlags);
+ dest.writeBoolean(mMustBeTask);
dest.writeInt(mOrder);
+ dest.writeTypedObject(mTopActivity, flags);
}
@NonNull
@@ -221,7 +277,10 @@
@Override
public String toString() {
StringBuilder out = new StringBuilder();
- out.append("{atype=" + WindowConfiguration.activityTypeToString(mActivityType));
+ out.append('{');
+ if (mNot) out.append("NOT ");
+ out.append("atype=" + WindowConfiguration.activityTypeToString(mActivityType));
+ out.append(" independent=" + mMustBeIndependent);
out.append(" modes=[");
if (mModes != null) {
for (int i = 0; i < mModes.length; ++i) {
@@ -229,7 +288,11 @@
}
}
out.append("]").toString();
+ out.append(" flags=" + TransitionInfo.flagsToString(mFlags));
+ out.append(" mustBeTask=" + mMustBeTask);
out.append(" order=" + containerOrderToString(mOrder));
+ out.append(" topActivity=").append(mTopActivity);
+ out.append("}");
return out.toString();
}
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index ebc66ef..b7de7b8 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -29,6 +29,8 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import android.annotation.IntDef;
@@ -42,7 +44,6 @@
import android.os.Parcelable;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import java.util.ArrayList;
import java.util.List;
@@ -90,8 +91,11 @@
/** The container is the display. */
public static final int FLAG_IS_DISPLAY = 1 << 5;
+ /** The container can show on top of lock screen. */
+ public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6;
+
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
- public static final int FLAG_FIRST_CUSTOM = 1 << 6;
+ public static final int FLAG_FIRST_CUSTOM = 1 << 7;
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
@@ -102,12 +106,13 @@
FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
FLAG_IS_VOICE_INTERACTION,
FLAG_IS_DISPLAY,
+ FLAG_OCCLUDES_KEYGUARD,
FLAG_FIRST_CUSTOM
})
public @interface ChangeFlags {}
- private final @WindowManager.TransitionOldType int mType;
- private final @WindowManager.TransitionFlags int mFlags;
+ private final @TransitionType int mType;
+ private final @TransitionFlags int mFlags;
private final ArrayList<Change> mChanges = new ArrayList<>();
private SurfaceControl mRootLeash;
@@ -116,8 +121,7 @@
private AnimationOptions mOptions;
/** @hide */
- public TransitionInfo(@WindowManager.TransitionOldType int type,
- @WindowManager.TransitionFlags int flags) {
+ public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
mType = type;
mFlags = flags;
}
@@ -173,7 +177,7 @@
mOptions = options;
}
- public int getType() {
+ public @TransitionType int getType() {
return mType;
}
@@ -234,7 +238,7 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags)
+ sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags)
+ " ro=" + mRootOffset + " c=[");
for (int i = 0; i < mChanges.size(); ++i) {
if (i > 0) {
@@ -283,6 +287,9 @@
if ((flags & FLAG_IS_DISPLAY) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY");
}
+ if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) {
+ sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD");
+ }
if ((flags & FLAG_FIRST_CUSTOM) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3c360fb..342df4f 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -410,7 +410,6 @@
/**
* Creates a new TaskFragment with the given options.
* @param taskFragmentOptions the options used to create the TaskFragment.
- * @hide
*/
@NonNull
public WindowContainerTransaction createTaskFragment(
@@ -426,7 +425,6 @@
/**
* Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
* @param taskFragment the TaskFragment to be removed.
- * @hide
*/
@NonNull
public WindowContainerTransaction deleteTaskFragment(
@@ -442,20 +440,21 @@
/**
* Starts an activity in the TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
- * {@link TaskFragmentCreationParams#fragmentToken}.
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @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).
- * @hide
*/
@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();
@@ -466,9 +465,8 @@
/**
* Moves an activity into the TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
- * {@link TaskFragmentCreationParams#fragmentToken}.
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
* @param activityToken activity to be reparented.
- * @hide
*/
@NonNull
public WindowContainerTransaction reparentActivityToTaskFragment(
@@ -488,7 +486,6 @@
* @param oldParent children of this TaskFragment will be reparented.
* @param newParent the new parent TaskFragment to move the children to. If {@code null}, the
* children will be moved to the leaf Task.
- * @hide
*/
@NonNull
public WindowContainerTransaction reparentChildren(
@@ -504,12 +501,37 @@
}
/**
+ * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent
+ * TaskFragments will be made invisible. This is similar to
+ * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
+ * fragmentTokens when that TaskFragments haven't been created (but will be created in the same
+ * {@link WindowContainerTransaction}).
+ * To reset it, pass {@code null} for {@code fragmentToken2}.
+ * @param fragmentToken1 client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @param fragmentToken2 client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}. If it is
+ * {@code null}, the transaction will reset the adjacent TaskFragment.
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction setAdjacentTaskFragments(
+ @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) {
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
+ .setContainer(fragmentToken1)
+ .setReparentContainer(fragmentToken2)
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+ }
+
+ /**
* When this {@link WindowContainerTransaction} failed to finish on the server side, it will
* trigger callback with this {@param errorCallbackToken}.
* @param errorCallbackToken client provided token that will be passed back as parameter in
* the callback if there is an error on the server side.
* @see ITaskFragmentOrganizer#onTaskFragmentError
- * @hide
*/
@NonNull
public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) {
@@ -906,6 +928,7 @@
public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10;
public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11;
public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12;
+ public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1060,6 +1083,11 @@
return mReparent;
}
+ @NonNull
+ public IBinder getCallingActivity() {
+ return mReparent;
+ }
+
public boolean getToTop() {
return mToTop;
}
@@ -1129,6 +1157,9 @@
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent
+ "}";
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
+ return "{SetAdjacentTaskFragments: container=" + mContainer
+ + " adjacentContainer=" + mReparent + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
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/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index 40ada0b..c00d16c 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.BadParcelableException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -109,17 +110,22 @@
// get annotations of content from intent.
private void getContentAnnotations(Intent intent) {
- ArrayList<String> annotations = intent.getStringArrayListExtra(
- Intent.EXTRA_CONTENT_ANNOTATIONS);
- if (annotations != null) {
- int size = annotations.size();
- if (size > NUM_OF_TOP_ANNOTATIONS_TO_USE) {
- size = NUM_OF_TOP_ANNOTATIONS_TO_USE;
+ try {
+ ArrayList<String> annotations = intent.getStringArrayListExtra(
+ Intent.EXTRA_CONTENT_ANNOTATIONS);
+ if (annotations != null) {
+ int size = annotations.size();
+ if (size > NUM_OF_TOP_ANNOTATIONS_TO_USE) {
+ size = NUM_OF_TOP_ANNOTATIONS_TO_USE;
+ }
+ mAnnotations = new String[size];
+ for (int i = 0; i < size; i++) {
+ mAnnotations[i] = annotations.get(i);
+ }
}
- mAnnotations = new String[size];
- for (int i = 0; i < size; i++) {
- mAnnotations[i] = annotations.get(i);
- }
+ } catch (BadParcelableException e) {
+ Log.i(TAG, "Couldn't unparcel intent annotations. Ignoring.");
+ mAnnotations = new String[0];
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index eeceafa..786af5f 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();
}
);
@@ -3452,8 +3454,6 @@
private View createProfileView(ViewGroup parent) {
View profileRow = mLayoutInflater.inflate(R.layout.chooser_profile_row, parent, false);
- profileRow.setBackground(
- getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
mProfileView = profileRow.findViewById(R.id.profile_button);
mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick);
updateProfileViewButton();
@@ -3599,10 +3599,6 @@
final ViewGroup viewGroup = (ViewGroup) holder.itemView;
int start = getListPosition(position);
int startType = getRowType(start);
- if (viewGroup.getForeground() == null && position > 0) {
- viewGroup.setForeground(
- getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
- }
int columnCount = holder.getColumnCount();
int end = start + columnCount - 1;
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/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index db5d066..84391c1 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -24,6 +24,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.util.EventLog;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -601,9 +602,14 @@
String messageWithStackTrace = message + '\n' + stackTrace;
Throwable throwable;
try {
- Class<?> clazz = Class.forName(className);
- Constructor<?> constructor = clazz.getConstructor(String.class);
- throwable = (Throwable) constructor.newInstance(messageWithStackTrace);
+ Class<?> clazz = Class.forName(className, true, Parcelable.class.getClassLoader());
+ if (Throwable.class.isAssignableFrom(clazz)) {
+ Constructor<?> constructor = clazz.getConstructor(String.class);
+ throwable = (Throwable) constructor.newInstance(messageWithStackTrace);
+ } else {
+ android.util.EventLog.writeEvent(0x534e4554, "186530450", -1, "");
+ throwable = new RuntimeException(className + ": " + messageWithStackTrace);
+ }
} catch (Throwable t) {
throwable = new RuntimeException(className + ": " + messageWithStackTrace);
throwable.addSuppressed(t);
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 1933c54..aca761d 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -112,13 +112,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;
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/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/view/InputBindResult.aidl b/core/java/com/android/internal/inputmethod/InputBindResult.aidl
similarity index 93%
rename from core/java/com/android/internal/view/InputBindResult.aidl
rename to core/java/com/android/internal/inputmethod/InputBindResult.aidl
index 7ff5c4e..4d4c22b 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package com.android.internal.inputmethod;
parcelable InputBindResult;
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
similarity index 86%
rename from core/java/com/android/internal/view/InputBindResult.java
rename to core/java/com/android/internal/inputmethod/InputBindResult.java
index 92105b9..1357bac 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -1,34 +1,34 @@
/*
- * Copyright (C) 2007-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * Copyright (C) 2007 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.
+ * 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.view;
+package com.android.internal.inputmethod;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
-import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.view.InputChannel;
+import com.android.internal.view.IInputMethodSession;
+
import java.lang.annotation.Retention;
/**
@@ -70,7 +70,7 @@
*
* <p>Some of fields such as {@link #channel} is not yet available.</p>
*
- * @see android.inputmethodservice.InputMethodService##onCreateInputMethodSessionInterface()
+ * @see android.inputmethodservice.InputMethodService#onCreateInputMethodSessionInterface()
**/
int SUCCESS_WAITING_IME_SESSION = 1;
/**
@@ -129,7 +129,8 @@
* Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to
* connect to an {@link android.inputmethodservice.InputMethodService} but failed.
*
- * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle)
+ * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int,
+ * android.os.UserHandle)
*/
int ERROR_IME_NOT_CONNECTED = 9;
/**
@@ -175,7 +176,6 @@
/**
* The input method service.
*/
- @UnsupportedAppUsage
public final IInputMethodSession method;
/**
@@ -188,26 +188,42 @@
* no input method will be bound.
*/
public final String id;
-
+
/**
* Sequence number of this binding.
*/
public final int sequence;
+ /**
+ * {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
+ */
public final boolean isInputMethodSuppressingSpellChecker;
- public InputBindResult(@ResultCode int _result,
- IInputMethodSession _method, InputChannel _channel, String _id, int _sequence,
+ /**
+ * Creates a new instance of {@link InputBindResult}.
+ *
+ * @param result A result code defined in {@link ResultCode}.
+ * @param method {@link IInputMethodSession} to interact with the IME.
+ * @param channel {@link InputChannel} to forward input events to the IME.
+ * @param id The {@link String} representations of the IME, which is the same as
+ * {@link android.view.inputmethod.InputMethodInfo#getId()} and
+ * {@link android.content.ComponentName#flattenToShortString()}.
+ * @param sequence A sequence number of this binding.
+ * @param isInputMethodSuppressingSpellChecker {@code true} if the IME explicitly specifies
+ * {@code suppressesSpellChecker="true"}.
+ */
+ public InputBindResult(@ResultCode int result,
+ IInputMethodSession method, InputChannel channel, String id, int sequence,
boolean isInputMethodSuppressingSpellChecker) {
- result = _result;
- method = _method;
- channel = _channel;
- id = _id;
- sequence = _sequence;
+ this.result = result;
+ this.method = method;
+ this.channel = channel;
+ this.id = id;
+ this.sequence = sequence;
this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
}
- InputBindResult(Parcel source) {
+ private InputBindResult(Parcel source) {
result = source.readInt();
method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
if (source.readInt() != 0) {
@@ -220,19 +236,19 @@
isInputMethodSuppressingSpellChecker = source.readBoolean();
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public String toString() {
- return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
+ return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
+ " sequence=" + sequence
+ " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
+ "}";
}
/**
- * Used to package this object into a {@link Parcel}.
- *
- * @param dest The {@link Parcel} to be written.
- * @param flags The flags used for parceling.
+ * {@inheritDoc}
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
@@ -252,7 +268,6 @@
/**
* Used to make this class parcelable.
*/
- @UnsupportedAppUsage
public static final Parcelable.Creator<InputBindResult> CREATOR =
new Parcelable.Creator<InputBindResult>() {
@Override
@@ -266,12 +281,15 @@
}
};
+ /**
+ * {@inheritDoc}
+ */
@Override
public int describeContents() {
return channel != null ? channel.describeContents() : 0;
}
- public String getResultString() {
+ private String getResultString() {
switch (result) {
case ResultCode.SUCCESS_WITH_IME_SESSION:
return "SUCCESS_WITH_IME_SESSION";
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 6838cbd..343a6e6 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -223,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<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 434f617..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
@@ -387,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);
}
}
@@ -512,7 +508,7 @@
*/
@GuardedBy("this")
public void clearPendingRemovedUidsLocked() {
- long cutOffTimeMs = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
+ long cutOffTimeMs = mClock.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
while (!mPendingRemovedUids.isEmpty()
&& mPendingRemovedUids.peek().getUidRemovalTimestamp() < cutOffTimeMs) {
mPendingRemovedUids.poll().removeLocked();
@@ -613,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;
@@ -1180,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;
@@ -1198,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);
}
/**
@@ -1755,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;
@@ -1783,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;
@@ -1795,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);
@@ -1825,7 +1796,7 @@
*/
@Override
public boolean reset(boolean detachIfReset) {
- return reset(detachIfReset, mClocks.elapsedRealtime() * 1000);
+ return reset(detachIfReset, mClock.elapsedRealtime() * 1000);
}
@Override
@@ -1971,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();
@@ -1982,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();
}
@@ -1993,7 +1964,7 @@
* be less than the values used for a previous invocation.
*/
public void endSample() {
- endSample(mClocks.elapsedRealtime() * 1000);
+ endSample(mClock.elapsedRealtime() * 1000);
}
/**
@@ -2028,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);
}
/**
@@ -2058,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);
}
/**
@@ -2148,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();
}
@@ -2220,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) {
@@ -2235,7 +2206,7 @@
}
public void abortLastDuration(BatteryStatsImpl stats) {
- abortLastDuration(stats, mClocks.elapsedRealtime());
+ abortLastDuration(stats, mClock.elapsedRealtime());
}
public void abortLastDuration(BatteryStatsImpl stats, long elapsedRealtimeMs) {
@@ -2303,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
@@ -2514,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;
}
@@ -2732,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);
}
/**
@@ -2744,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. */
@@ -3168,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;
@@ -3178,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;
@@ -3191,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;
@@ -3204,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;
@@ -3213,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;
@@ -3618,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);
@@ -3716,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);
@@ -3878,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,
@@ -3923,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,
@@ -3936,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);
}
@@ -3948,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,
@@ -3968,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,
@@ -3981,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) {
@@ -3993,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,
@@ -4014,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,
@@ -4031,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) {
@@ -4045,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) {
@@ -4060,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) {
@@ -4075,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,
@@ -4091,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,
@@ -4103,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,
@@ -4114,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,
@@ -4126,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,
@@ -4164,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,
@@ -4223,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++) {
@@ -4238,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++) {
@@ -4259,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());
}
}
@@ -4269,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,
@@ -4340,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,
@@ -4423,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,
@@ -4450,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,
@@ -4502,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,
@@ -4525,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,
@@ -4537,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,
@@ -4575,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,
@@ -4587,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,
@@ -4635,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) {
@@ -4705,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) {
@@ -4722,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) {
@@ -4741,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,
@@ -4820,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) {
@@ -4848,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")
@@ -4949,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) {
@@ -4977,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) {
@@ -4988,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,
@@ -4998,7 +4969,7 @@
}
public void noteInteractiveLocked(boolean interactive) {
- noteInteractiveLocked(interactive, mClocks.elapsedRealtime());
+ noteInteractiveLocked(interactive, mClock.elapsedRealtime());
}
public void noteInteractiveLocked(boolean interactive, long elapsedRealtimeMs) {
@@ -5015,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,
@@ -5038,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,
@@ -5086,7 +5057,7 @@
}
public void notePowerSaveModeLocked(boolean enabled) {
- notePowerSaveModeLocked(enabled, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePowerSaveModeLocked(enabled, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
/**
@@ -5133,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,
@@ -5211,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,
@@ -5227,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,
@@ -5248,7 +5219,7 @@
}
void stopAllGpsSignalQualityTimersLocked(int except) {
- stopAllGpsSignalQualityTimersLocked(except, mClocks.elapsedRealtime());
+ stopAllGpsSignalQualityTimersLocked(except, mClock.elapsedRealtime());
}
void stopAllGpsSignalQualityTimersLocked(int except, long elapsedRealtimeMs) {
@@ -5264,7 +5235,7 @@
@UnsupportedAppUsage
public void notePhoneOnLocked() {
- notePhoneOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePhoneOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5280,7 +5251,7 @@
@UnsupportedAppUsage
public void notePhoneOffLocked() {
- notePhoneOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePhoneOffLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5302,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);
@@ -5312,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());
}
}
}
@@ -5453,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,
@@ -5465,7 +5436,7 @@
@UnsupportedAppUsage
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
notePhoneSignalStrengthLocked(signalStrength,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength,
@@ -5479,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,
@@ -5522,7 +5493,7 @@
}
public void noteWifiOnLocked() {
- noteWifiOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5538,7 +5509,7 @@
}
public void noteWifiOffLocked() {
- noteWifiOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiOffLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5555,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) {
@@ -5574,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) {
@@ -5595,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) {
@@ -5614,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) {
@@ -5634,7 +5605,7 @@
}
public void noteResetAudioLocked() {
- noteResetAudioLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetAudioLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5653,7 +5624,7 @@
}
public void noteResetVideoLocked() {
- noteResetVideoLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetVideoLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5672,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) {
@@ -5682,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) {
@@ -5693,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,
@@ -5704,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) {
@@ -5714,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) {
@@ -5731,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) {
@@ -5751,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) {
@@ -5768,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) {
@@ -5788,7 +5759,7 @@
}
public void noteResetCameraLocked() {
- noteResetCameraLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetCameraLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5807,7 +5778,7 @@
}
public void noteResetFlashlightLocked() {
- noteResetFlashlightLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetFlashlightLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5842,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,
@@ -5887,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,
@@ -5908,7 +5879,7 @@
}
public void noteResetBluetoothScanLocked() {
- noteResetBluetoothScanLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetBluetoothScanLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5928,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,
@@ -5961,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,
@@ -5988,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) {
@@ -6023,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,
@@ -6066,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) {
@@ -6100,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) {
@@ -6117,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,
@@ -6150,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) {
@@ -6182,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) {
@@ -6199,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) {
@@ -6217,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) {
@@ -6233,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) {
@@ -6250,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,
@@ -6261,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) {
@@ -6274,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) {
@@ -6298,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) {
@@ -6322,7 +6293,7 @@
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
noteFullWifiLockAcquiredFromSourceLocked(ws,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws,
@@ -6345,7 +6316,7 @@
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
noteFullWifiLockReleasedFromSourceLocked(ws,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws,
@@ -6367,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,
@@ -6389,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,
@@ -6412,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,
@@ -6433,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) {
@@ -6509,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,
@@ -7011,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;
}
@@ -7383,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) {
@@ -7409,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);
@@ -7625,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);
@@ -7645,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);
@@ -7665,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);
}
@@ -7715,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);
@@ -7904,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;
@@ -7928,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;
@@ -7952,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;
@@ -7976,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;
@@ -8000,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;
@@ -8008,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;
@@ -8016,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);
}
@@ -8025,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);
}
@@ -8034,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);
}
@@ -8112,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;
@@ -8298,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);
}
}
@@ -8362,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);
}
}
@@ -9159,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));
}
}
@@ -9169,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));
}
}
@@ -9214,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 {
@@ -9244,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);
@@ -9294,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 {
@@ -9326,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;
@@ -9536,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);
}
/**
@@ -9552,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) {
@@ -9649,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) {
@@ -10151,7 +10123,7 @@
@UnsupportedAppUsage
public void startLaunchedLocked() {
- startLaunchedLocked(mBsi.mClocks.uptimeMillis());
+ startLaunchedLocked(mBsi.mClock.uptimeMillis());
}
public void startLaunchedLocked(long uptimeMs) {
@@ -10164,7 +10136,7 @@
@UnsupportedAppUsage
public void stopLaunchedLocked() {
- stopLaunchedLocked(mBsi.mClocks.uptimeMillis());
+ stopLaunchedLocked(mBsi.mClock.uptimeMillis());
}
public void stopLaunchedLocked(long uptimeMs) {
@@ -10182,7 +10154,7 @@
@UnsupportedAppUsage
public void startRunningLocked() {
- startRunningLocked(mBsi.mClocks.uptimeMillis());
+ startRunningLocked(mBsi.mClock.uptimeMillis());
}
public void startRunningLocked(long uptimeMs) {
@@ -10195,7 +10167,7 @@
@UnsupportedAppUsage
public void stopRunningLocked() {
- stopRunningLocked(mBsi.mClocks.uptimeMillis());
+ stopRunningLocked(mBsi.mClock.uptimeMillis());
}
public void stopRunningLocked(long uptimeMs) {
@@ -10254,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,
@@ -10419,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;
@@ -10470,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;
@@ -10480,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;
}
@@ -10489,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;
}
@@ -10498,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;
}
@@ -10586,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;
@@ -10608,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);
@@ -10626,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++) {
@@ -10660,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);
@@ -10706,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;
@@ -10778,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);
@@ -10806,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;
@@ -11171,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;
@@ -11203,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;
@@ -12739,7 +12711,7 @@
* Read and distribute kernel wake lock use across apps.
*/
public void updateKernelWakelocksLocked() {
- updateKernelWakelocksLocked(mClocks.elapsedRealtime() * 1000);
+ updateKernelWakelocksLocked(mClock.elapsedRealtime() * 1000);
}
/**
@@ -12760,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);
}
@@ -12802,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) {
@@ -12815,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);
@@ -13113,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);
@@ -13166,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];
@@ -13222,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");
}
@@ -13283,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) -> {
@@ -13359,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");
}
@@ -13407,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)) {
@@ -13423,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");
}
@@ -13440,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) -> {
@@ -13462,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");
}
@@ -13641,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);
@@ -13683,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,
@@ -13920,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
@@ -14175,7 +14147,7 @@
* @return battery uptime in microseconds
*/
protected long getBatteryUptimeLocked() {
- return getBatteryUptimeLocked(mClocks.uptimeMillis());
+ return getBatteryUptimeLocked(mClock.uptimeMillis());
}
/**
@@ -14348,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) {
@@ -14410,7 +14382,7 @@
*/
@UnsupportedAppUsage
public void removeUidStatsLocked(int uid) {
- removeUidStatsLocked(uid, mClocks.elapsedRealtime());
+ removeUidStatsLocked(uid, mClock.elapsedRealtime());
}
/**
@@ -14464,7 +14436,7 @@
*/
@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());
}
/**
@@ -14483,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());
}
/**
@@ -14503,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,
@@ -14514,7 +14486,7 @@
}
public void shutdownLocked() {
- recordShutdownLocked(mClocks.currentTimeMillis(), mClocks.elapsedRealtime());
+ recordShutdownLocked(mClock.currentTimeMillis(), mClock.elapsedRealtime());
writeSyncLocked();
mShuttingDown = true;
}
@@ -14736,7 +14708,7 @@
mNumSingleUidCpuTimeReads = 0;
mNumBatchedSingleUidCpuTimeReads = 0;
- mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
+ mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
}
}
@@ -14745,7 +14717,7 @@
if (oldDelayMillis != newDelayMillis) {
mNumSingleUidCpuTimeReads = 0;
mNumBatchedSingleUidCpuTimeReads = 0;
- mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
+ mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
}
}
@@ -14925,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);
}
@@ -15059,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() {
@@ -15117,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);
@@ -15368,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);
@@ -15677,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);
@@ -15697,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);
@@ -15745,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);
@@ -15799,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()) {
@@ -15809,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);
}
@@ -15820,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);
}
@@ -15832,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);
}
@@ -15844,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);
}
@@ -15856,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);
}
@@ -15868,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);
}
@@ -15972,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);
}
@@ -16078,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);
}
@@ -16107,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();
@@ -16115,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);
@@ -16139,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);
}
@@ -16178,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);
@@ -16221,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++) {
@@ -16257,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,
@@ -16303,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();
@@ -16343,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);
}
}
@@ -16352,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);
}
}
@@ -16362,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);
}
}
@@ -16372,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);
}
}
@@ -16382,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);
}
}
@@ -16402,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);
@@ -16433,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);
@@ -16790,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/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 6ce7cea..be91aac 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -220,8 +220,9 @@
public CallSession callStarted(Binder binder, int code, int workSourceUid) {
noteNativeThreadId();
+ boolean collectCpu = canCollect();
// We always want to collect data for latency if it's enabled, regardless of device state.
- if (!mCollectLatencyData && !canCollect()) {
+ if (!mCollectLatencyData && !collectCpu) {
return null;
}
@@ -233,7 +234,7 @@
s.timeStarted = -1;
s.recordedCall = shouldRecordDetailedData();
- if (mRecordingAllTransactionsForUid || s.recordedCall) {
+ if (collectCpu && (mRecordingAllTransactionsForUid || s.recordedCall)) {
s.cpuTimeStarted = getThreadTimeMicro();
s.timeStarted = getElapsedRealtimeMicro();
} else if (mCollectLatencyData) {
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/os/ProcLocksReader.java b/core/java/com/android/internal/os/ProcLocksReader.java
new file mode 100644
index 0000000..bd3115fc5
--- /dev/null
+++ b/core/java/com/android/internal/os/ProcLocksReader.java
@@ -0,0 +1,89 @@
+/*
+ * 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 com.android.internal.util.ProcFileReader;
+
+import libcore.io.IoUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Reads and parses {@code locks} files in the {@code proc} filesystem.
+ * A typical example of /proc/locks
+ *
+ * 1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335
+ * 2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF
+ * 2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF
+ * 2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF
+ * 3: POSIX ADVISORY READ 3888 fd:09:13992 128 128
+ * 4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335
+ */
+public class ProcLocksReader {
+ private final String mPath;
+
+ public ProcLocksReader() {
+ mPath = "/proc/locks";
+ }
+
+ public ProcLocksReader(String path) {
+ mPath = path;
+ }
+
+ /**
+ * Checks if a process corresponding to a specific pid owns any file locks.
+ * @param pid The process ID for which we want to know the existence of file locks.
+ * @return true If the process holds any file locks, false otherwise.
+ * @throws IOException if /proc/locks can't be accessed.
+ */
+ public boolean hasFileLocks(int pid) throws Exception {
+ ProcFileReader reader = null;
+ long last = -1;
+ long id; // ordinal position of the lock in the list
+ int owner; // the PID of the process that owns the lock
+
+ try {
+ reader = new ProcFileReader(new FileInputStream(mPath));
+
+ while (reader.hasMoreData()) {
+ id = reader.nextLong(true); // lock id
+ if (id == last) {
+ reader.finishLine(); // blocked lock
+ continue;
+ }
+
+ reader.nextIgnored(); // lock type: POSIX?
+ reader.nextIgnored(); // lock type: MANDATORY?
+ reader.nextIgnored(); // lock type: RW?
+
+ owner = reader.nextInt(); // pid
+ if (owner == pid) {
+ return true;
+ }
+ reader.finishLine();
+ last = id;
+ }
+ } catch (IOException e) {
+ // TODO: let ProcFileReader log the failed line
+ throw new Exception("Exception parsing /proc/locks");
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 4f940db..84a7f2f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -25,7 +25,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.service.notification.StatusBarNotification;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
@@ -192,12 +192,12 @@
* stacks.
* @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
* @param behavior the behavior of the focused window.
- * @param requestedState the collection of the requested visibilities of system insets.
+ * @param requestedVisibilities the collection of the requested visibilities of system insets.
* @param packageName the package name of the focused app.
*/
void onSystemBarAttributesChanged(int displayId, int appearance,
in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- int behavior, in InsetsState requestedVisibilities, String packageName);
+ int behavior, in InsetsVisibilities requestedVisibilities, String packageName);
/**
* Notifies System UI to show transient bars. The transient bars are system bars, e.g., status
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 2fd1691..4dcc82e 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -21,7 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.view.AppearanceRegion;
@@ -40,14 +40,14 @@
public final IBinder mImeToken;
public final boolean mNavbarColorManagedByIme;
public final int mBehavior;
- public final InsetsState mRequestedState;
+ public final InsetsVisibilities mRequestedVisibilities;
public final String mPackageName;
public final int[] mTransientBarTypes;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
- boolean navbarColorManagedByIme, int behavior, InsetsState requestedState,
+ boolean navbarColorManagedByIme, int behavior, InsetsVisibilities requestedVisibilities,
String packageName, @NonNull int[] transientBarTypes) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
@@ -60,7 +60,7 @@
mImeToken = imeToken;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mRequestedState = requestedState;
+ mRequestedVisibilities = requestedVisibilities;
mPackageName = packageName;
mTransientBarTypes = transientBarTypes;
}
@@ -83,7 +83,7 @@
dest.writeStrongBinder(mImeToken);
dest.writeBoolean(mNavbarColorManagedByIme);
dest.writeInt(mBehavior);
- dest.writeTypedObject(mRequestedState, 0);
+ dest.writeTypedObject(mRequestedVisibilities, 0);
dest.writeString(mPackageName);
dest.writeIntArray(mTransientBarTypes);
}
@@ -108,13 +108,14 @@
final IBinder imeToken = source.readStrongBinder();
final boolean navbarColorManagedByIme = source.readBoolean();
final int behavior = source.readInt();
- final InsetsState requestedState = source.readTypedObject(InsetsState.CREATOR);
+ final InsetsVisibilities requestedVisibilities =
+ source.readTypedObject(InsetsVisibilities.CREATOR);
final String packageName = source.readString();
final int[] transientBarTypes = source.createIntArray();
return new RegisterStatusBarResult(icons, disabledFlags1, appearance,
appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher,
disabledFlags2, imeToken, navbarColorManagedByIme, behavior,
- requestedState, packageName, transientBarTypes);
+ requestedVisibilities, packageName, transientBarTypes);
}
@Override
diff --git a/core/java/com/android/internal/util/ProcFileReader.java b/core/java/com/android/internal/util/ProcFileReader.java
index ead58c7d..0dd8ad8 100644
--- a/core/java/com/android/internal/util/ProcFileReader.java
+++ b/core/java/com/android/internal/util/ProcFileReader.java
@@ -28,8 +28,8 @@
* requires each line boundary to be explicitly acknowledged using
* {@link #finishLine()}. Assumes {@link StandardCharsets#US_ASCII} encoding.
* <p>
- * Currently doesn't support formats based on {@code \0}, tabs, or repeated
- * delimiters.
+ * Currently doesn't support formats based on {@code \0}, tabs.
+ * Consecutive spaces are treated as a single delimiter.
*/
public class ProcFileReader implements Closeable {
private final InputStream mStream;
@@ -75,6 +75,11 @@
private void consumeBuf(int count) throws IOException {
// TODO: consider moving to read pointer, but for now traceview says
// these copies aren't a bottleneck.
+
+ // skip all consecutive delimiters.
+ while (count < mTail && mBuffer[count] == ' ') {
+ count++;
+ }
System.arraycopy(mBuffer, count, mBuffer, 0, mTail - count);
mTail -= count;
if (mTail == 0) {
@@ -159,11 +164,18 @@
* Parse and return next token as base-10 encoded {@code long}.
*/
public long nextLong() throws IOException {
+ return nextLong(false);
+ }
+
+ /**
+ * Parse and return next token as base-10 encoded {@code long}.
+ */
+ public long nextLong(boolean stopAtInvalid) throws IOException {
final int tokenIndex = nextTokenIndex();
if (tokenIndex == -1) {
throw new ProtocolException("Missing required long");
} else {
- return parseAndConsumeLong(tokenIndex);
+ return parseAndConsumeLong(tokenIndex, stopAtInvalid);
}
}
@@ -176,7 +188,7 @@
if (tokenIndex == -1) {
return def;
} else {
- return parseAndConsumeLong(tokenIndex);
+ return parseAndConsumeLong(tokenIndex, false);
}
}
@@ -186,7 +198,10 @@
return s;
}
- private long parseAndConsumeLong(int tokenIndex) throws IOException {
+ /**
+ * If stopAtInvalid is true, don't throw IOException but return whatever parsed so far.
+ */
+ private long parseAndConsumeLong(int tokenIndex, boolean stopAtInvalid) throws IOException {
final boolean negative = mBuffer[0] == '-';
// TODO: refactor into something like IntegralToString
@@ -194,7 +209,11 @@
for (int i = negative ? 1 : 0; i < tokenIndex; i++) {
final int digit = mBuffer[i] - '0';
if (digit < 0 || digit > 9) {
- throw invalidLong(tokenIndex);
+ if (stopAtInvalid) {
+ break;
+ } else {
+ throw invalidLong(tokenIndex);
+ }
}
// always parse as negative number and apply sign later; this
@@ -226,6 +245,18 @@
return (int) value;
}
+ /**
+ * Bypass the next token.
+ */
+ public void nextIgnored() throws IOException {
+ final int tokenIndex = nextTokenIndex();
+ if (tokenIndex == -1) {
+ throw new ProtocolException("Missing required token");
+ } else {
+ consumeBuf(tokenIndex + 1);
+ }
+ }
+
@Override
public void close() throws IOException {
mStream.close();
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 9ae3ab2..191bdf3 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -18,12 +18,9 @@
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;
@@ -50,7 +47,6 @@
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputConnectionProtoDumper;
-import com.android.internal.os.SomeArgs;
import java.lang.ref.WeakReference;
@@ -58,43 +54,13 @@
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;
-
-
@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 Looper mMainLooper;
+ private final Handler mH;
+
private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mFinished = false;
@@ -102,23 +68,12 @@
private final InputMethodManager mParentInputMethodManager;
private final WeakReference<View> mServedView;
- class MyHandler extends Handler {
- MyHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- executeMessage(msg);
- }
- }
-
public IInputConnectionWrapper(@NonNull Looper mainLooper,
@NonNull InputConnection inputConnection,
@NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
mInputConnection = inputConnection;
mMainLooper = mainLooper;
- mH = new MyHandler(mMainLooper);
+ mH = new Handler(mMainLooper);
mParentInputMethodManager = inputMethodManager;
mServedView = new WeakReference<>(servedView);
}
@@ -196,15 +151,93 @@
}
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
+ try {
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getTextAfterCursor(length, flags);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(
+ length, 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_TEXT_BEFORE_CURSOR, length, flags, callback));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
+ try {
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getTextBeforeCursor(length, flags);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(
+ length, 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_SELECTED_TEXT, flags, 0 /* unused */, callback));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
+ try {
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getSelectedText on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getSelectedText(flags);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
/**
@@ -214,87 +247,347 @@
*/
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));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
+ try {
+ final InputConnection ic = getInputConnection();
+ final SurroundingText result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getSurroundingText on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getSurroundingText(beforeLength, afterLength, flags);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
+ beforeLength, afterLength, flags, result);
+ 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
- dispatchMessage(
- mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
+ try {
+ final InputConnection ic = getInputConnection();
+ final int result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+ result = 0;
+ } else {
+ result = ic.getCursorCapsMode(reqModes);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
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));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
+ try {
+ 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, flags);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(
+ request, 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void commitText(CharSequence text, int newCursorPosition) {
- dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitText on inactive InputConnection");
+ return;
+ }
+ ic.commitText(text, newCursorPosition);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void commitCompletion(CompletionInfo text) {
- dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCompletion on inactive InputConnection");
+ return;
+ }
+ ic.commitCompletion(text);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void commitCorrection(CorrectionInfo info) {
- dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCorrection on inactive InputConnection");
+ return;
+ }
+ ic.commitCorrection(info);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void setSelection(int start, int end) {
- dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setSelection on inactive InputConnection");
+ return;
+ }
+ ic.setSelection(start, end);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void performEditorAction(int id) {
- dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performEditorAction on inactive InputConnection");
+ return;
+ }
+ ic.performEditorAction(id);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
-
+
public void performContextMenuAction(int id) {
- dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+ return;
+ }
+ ic.performContextMenuAction(id);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
-
+
public void setComposingRegion(int start, int end) {
- dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingRegion on inactive InputConnection");
+ return;
+ }
+ ic.setComposingRegion(start, end);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void setComposingText(CharSequence text, int newCursorPosition) {
- dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingText on inactive InputConnection");
+ return;
+ }
+ ic.setComposingText(text, newCursorPosition);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void finishComposingText() {
- dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
+ try {
+ if (isFinished()) {
+ // In this case, #finishComposingText() is guaranteed to be called already.
+ // There should be no negative impact if we ignore this call silently.
+ if (DEBUG) {
+ Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+ }
+ return;
+ }
+ 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) {
+ Log.w(TAG, "finishComposingText on inactive InputConnection");
+ return;
+ }
+ ic.finishComposingText();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void sendKeyEvent(KeyEvent event) {
- dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+ return;
+ }
+ ic.sendKeyEvent(event);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void clearMetaKeyStates(int states) {
- dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+ return;
+ }
+ ic.clearMetaKeyStates(states);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void deleteSurroundingText(int beforeLength, int afterLength) {
- dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
- beforeLength, afterLength));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingText(beforeLength, afterLength);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
- dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
- beforeLength, afterLength));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT,
+ "InputConnection#deleteSurroundingTextInCodePoints");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void beginBatchEdit() {
- dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.beginBatchEdit();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void endBatchEdit() {
- dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "endBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.endBatchEdit();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
/**
@@ -303,29 +596,123 @@
* @see InputConnection#performSpellCheck()
*/
public void performSpellCheck() {
- dispatchMessage(obtainMessage(DO_PERFORM_SPELL_CHECK));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performSpellCheck on inactive InputConnection");
+ return;
+ }
+ ic.performSpellCheck();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void performPrivateCommand(String action, Bundle data) {
- dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performPrivateCommand on inactive InputConnection");
+ return;
+ }
+ ic.performPrivateCommand(action, data);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_REQUEST_CURSOR_UPDATES, cursorUpdateMode,
- 0 /* unused */, callback));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
+ try {
+ final InputConnection ic = getInputConnection();
+ final boolean result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+ result = false;
+ } else {
+ result = ic.requestCursorUpdates(cursorUpdateMode);
+ }
+ try {
+ callback.onResult(result);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
+ + " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
public void closeConnection() {
- dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
+ dispatch(() -> {
+ // 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 closeConnection() tasks 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);
+ }
+ });
}
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));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
+ try {
+ final InputConnection ic = getInputConnection();
+ final boolean result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitContent on inactive InputConnection");
+ result = false;
+ } else {
+ if (inputContentInfo == null || !inputContentInfo.validate()) {
+ Log.w(TAG, "commitContent with invalid inputContentInfo="
+ + inputContentInfo);
+ result = false;
+ } else {
+ 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);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
/**
@@ -334,599 +721,30 @@
* <p>See {@link InputConnection#setImeConsumesInput(boolean)}.
*/
public void setImeConsumesInput(boolean imeConsumesInput) {
- dispatchMessage(obtainMessageB(DO_SET_IME_CONSUMES_INPUT, imeConsumesInput));
+ dispatch(() -> {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setImeConsumesInput");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setImeConsumesInput on inactive InputConnection");
+ return;
+ }
+ ic.setImeConsumesInput(imeConsumesInput);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ });
}
- void dispatchMessage(Message msg) {
+ private void dispatch(@NonNull Runnable runnable) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
// main thread.
- if (Looper.myLooper() == mMainLooper) {
- executeMessage(msg);
- msg.recycle();
+ if (mMainLooper.isCurrentThread()) {
+ runnable.run();
return;
}
-
- mH.sendMessage(msg);
- }
- void executeMessage(Message msg) {
- byte[] icProto;
- switch (msg.what) {
- case DO_GET_TEXT_AFTER_CURSOR: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
- try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
- 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);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(msg.arg1,
- msg.arg2, 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_GET_TEXT_BEFORE_CURSOR: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
- try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
- 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);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(msg.arg1,
- msg.arg2, 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_GET_SELECTED_TEXT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
- try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
- 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);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(msg.arg1,
- 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_GET_SURROUNDING_TEXT: {
- final SomeArgs args = (SomeArgs) msg.obj;
- 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 InputConnection ic = getInputConnection();
- final SurroundingText result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "getSurroundingText on inactive InputConnection");
- result = null;
- } else {
- result = ic.getSurroundingText(beforeLength, afterLength, flags);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
- beforeLength, afterLength, flags, result);
- 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
- }
- return;
- }
- case DO_GET_CURSOR_CAPS_MODE: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
- try {
- final IIntResultCallback callback = (IIntResultCallback) msg.obj;
- 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);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(msg.arg1,
- 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_GET_EXTRACTED_TEXT: {
- final SomeArgs args = (SomeArgs) msg.obj;
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
- try {
- final ExtractedTextRequest request = (ExtractedTextRequest) args.arg1;
- final IExtractedTextResultCallback callback =
- (IExtractedTextResultCallback) args.arg2;
- 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);
- }
- if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(request,
- msg.arg1, 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);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
- }
- return;
- }
- case DO_COMMIT_TEXT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitText on inactive InputConnection");
- return;
- }
- ic.commitText((CharSequence) msg.obj, msg.arg1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_SET_SELECTION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setSelection on inactive InputConnection");
- return;
- }
- ic.setSelection(msg.arg1, msg.arg2);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_PERFORM_EDITOR_ACTION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performEditorAction on inactive InputConnection");
- return;
- }
- ic.performEditorAction(msg.arg1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_PERFORM_CONTEXT_MENU_ACTION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performContextMenuAction on inactive InputConnection");
- return;
- }
- ic.performContextMenuAction(msg.arg1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_COMMIT_COMPLETION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitCompletion on inactive InputConnection");
- return;
- }
- ic.commitCompletion((CompletionInfo) msg.obj);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_COMMIT_CORRECTION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitCorrection on inactive InputConnection");
- return;
- }
- ic.commitCorrection((CorrectionInfo) msg.obj);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_SET_COMPOSING_TEXT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setComposingText on inactive InputConnection");
- return;
- }
- ic.setComposingText((CharSequence) msg.obj, msg.arg1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_SET_COMPOSING_REGION: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setComposingRegion on inactive InputConnection");
- return;
- }
- ic.setComposingRegion(msg.arg1, msg.arg2);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_FINISH_COMPOSING_TEXT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
- try {
- if (isFinished()) {
- // In this case, #finishComposingText() is guaranteed to be called already.
- // There should be no negative impact if we ignore this call silently.
- if (DEBUG) {
- Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
- }
- return;
- }
- 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) {
- Log.w(TAG, "finishComposingText on inactive InputConnection");
- return;
- }
- ic.finishComposingText();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_SEND_KEY_EVENT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "sendKeyEvent on inactive InputConnection");
- return;
- }
- ic.sendKeyEvent((KeyEvent) msg.obj);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_CLEAR_META_KEY_STATES: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
- return;
- }
- ic.clearMetaKeyStates(msg.arg1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_DELETE_SURROUNDING_TEXT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
- return;
- }
- ic.deleteSurroundingText(msg.arg1, msg.arg2);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT,
- "InputConnection#deleteSurroundingTextInCodePoints");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
- return;
- }
- ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_BEGIN_BATCH_EDIT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "beginBatchEdit on inactive InputConnection");
- return;
- }
- ic.beginBatchEdit();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_END_BATCH_EDIT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "endBatchEdit on inactive InputConnection");
- return;
- }
- ic.endBatchEdit();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_PERFORM_SPELL_CHECK: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performSpellCheck on inactive InputConnection");
- return;
- }
- ic.performSpellCheck();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_PERFORM_PRIVATE_COMMAND: {
- final SomeArgs args = (SomeArgs) msg.obj;
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
- try {
- final String action = (String) args.arg1;
- final Bundle data = (Bundle) args.arg2;
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performPrivateCommand on inactive InputConnection");
- return;
- }
- ic.performPrivateCommand(action, data);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
- }
- return;
- }
- case DO_REQUEST_CURSOR_UPDATES: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
- try {
- final IBooleanResultCallback callback = (IBooleanResultCallback) msg.obj;
- 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);
- }
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
- + " result=" + result, e);
- }
- } 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;
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
- try {
- final IBooleanResultCallback callback = (IBooleanResultCallback) args.arg3;
- 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);
- }
- }
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to commitContent()."
- + " result=" + result, e);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
- }
- return;
- }
- case DO_SET_IME_CONSUMES_INPUT: {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT,
- "InputConnection#setImeConsumesInput");
- try {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG,
- "setImeConsumesInput on inactive InputConnection");
- return;
- }
- ic.setImeConsumesInput(msg.arg1 == 1);
- } 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);
+ mH.post(runnable);
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index f5c2a2a..e72afdd 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -16,7 +16,7 @@
package com.android.internal.view;
-import com.android.internal.view.InputBindResult;
+import com.android.internal.inputmethod.InputBindResult;
/**
* Interface a client of the IInputMethodManager implements, to identify
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index d40c064..4b72355 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -21,7 +21,7 @@
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.EditorInfo;
-import com.android.internal.view.InputBindResult;
+import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
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..e9e2fff 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",
@@ -407,9 +408,4 @@
export_header_lib_headers: [
"jni_headers",
],
- apex_available: [
- "//apex_available:platform",
- "com.android.media",
- "com.android.media.swcodec",
- ],
}
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/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c6317cc..fffc37c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -618,7 +618,11 @@
<protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
<protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+
<protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+ <protected-broadcast android:name="android.server.notification.action.ENABLE_NAS" />
+ <protected-broadcast android:name="android.server.notification.action.DISABLE_NAS" />
+ <protected-broadcast android:name="android.server.notification.action.LEARNMORE_NAS" />
<protected-broadcast android:name="com.android.internal.location.ALARM_WAKEUP" />
<protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
@@ -3464,6 +3468,13 @@
<permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
android:protectionLevel="signature" />
+ <!-- Allows an application to trigger profcollect report upload via shell.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
@hide
@SystemApi -->
@@ -3505,7 +3516,7 @@
use by third party apps.
@hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|installer" />
+ android:protectionLevel="signature|privileged|installer|role" />
<!-- @SystemApi Allows an application to update the user app op restrictions.
Not for use by third party apps.
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 7a8da36..684202b 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -25,3 +25,6 @@
toddke@google.com
tsuji@google.com
yamasani@google.com
+
+# Multiuser
+per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
diff --git a/core/res/res/drawable/chooser_row_layer_list.xml b/core/res/res/drawable/chooser_row_layer_list.xml
index 0800815..f5ba1e9 100644
--- a/core/res/res/drawable/chooser_row_layer_list.xml
+++ b/core/res/res/drawable/chooser_row_layer_list.xml
@@ -17,9 +17,11 @@
*/
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:bottom="-5dp" android:left="-5dp" android:right="-5dp">
+ <item>
<shape android:shape="rectangle">
- <stroke android:width="1dp" android:color="@color/chooser_row_divider"/>
+ <solid android:color="?android:attr/colorAccentSecondary"/>
+ <size android:width="128dp" android:height="2dp"/>
+ <corners android:radius="2dp" />
</shape>
</item>
</layer-list>
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/layout/chooser_az_label_row.xml b/core/res/res/layout/chooser_az_label_row.xml
index 1b733fc..baf07ce 100644
--- a/core/res/res/layout/chooser_az_label_row.xml
+++ b/core/res/res/layout/chooser_az_label_row.xml
@@ -15,17 +15,12 @@
~ limitations under the License
-->
-<!-- Separator applied as background -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:text="@string/chooser_all_apps_button_label"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:contentDescription="@string/chooser_all_apps_button_label"
- android:background="@drawable/chooser_row_layer_list"
- android:textAppearance="?attr/textAppearanceSmall"
- android:textColor="?attr/textColorSecondary"
- android:textSize="14sp"
- android:singleLine="true"
+ android:src="@drawable/chooser_row_layer_list"
android:paddingTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:scaleType="center"
android:gravity="center"/>
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index 0b7b49c..aa050f3 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -21,12 +21,11 @@
android:padding="0dp"
android:orientation="vertical">
- <View android:id="@+id/splashscreen_icon_view"
+ <ImageView android:id="@+id/splashscreen_icon_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:padding="0dp"
- android:background="@null"
android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7bcd93e..7e3f16b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2080,7 +2080,7 @@
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع الاتصال"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"مكالمة واردة"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"مكالمة جارية"</string>
- <string name="call_notification_screening_text" msgid="8396931408268940208">"رصد مكالمة واردة"</string>
+ <string name="call_notification_screening_text" msgid="8396931408268940208">"يتم فحص المكالمة الواردة"</string>
<plurals name="selected_count" formatted="false" msgid="3946212171128200491">
<item quantity="zero">تم اختيار <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر</item>
<item quantity="two">تم اختيار عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)</item>
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-de/strings.xml b/core/res/res/values-de/strings.xml
index ecb8070..5245437 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -984,7 +984,7 @@
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchtest du diese Seite wirklich verlassen?"</string>
<string name="save_password_label" msgid="9161712335355510035">"Bestätigen"</string>
<string name="double_tap_toast" msgid="7065519579174882778">"Tipp: Zum Vergrößern und Verkleinern doppeltippen"</string>
- <string name="autofill_this_form" msgid="3187132440451621492">"AutoFill"</string>
+ <string name="autofill_this_form" msgid="3187132440451621492">"Automatisches Ausfüllen"</string>
<string name="setup_autofill" msgid="5431369130866618567">"Autom.Ausfüll.konf."</string>
<string name="autofill_window_title" msgid="4379134104008111961">"Mit <xliff:g id="SERVICENAME">%1$s</xliff:g> automatisch ausfüllen"</string>
<string name="autofill_address_name_separator" msgid="8190155636149596125">" "</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..716b2c8 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>
@@ -271,7 +271,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"Ajustes"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Asistencia"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo seguro"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo de seguridad"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"> 999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</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-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 07e4ffc..2d8b565 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1952,7 +1952,7 @@
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<string name="call_notification_answer_action" msgid="5999246836247132937">"जवाफ दिनुहोस्"</string>
<string name="call_notification_answer_video_action" msgid="2086030940195382249">"भिडियो"</string>
- <string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार गर्नुहोस्"</string>
+ <string name="call_notification_decline_action" msgid="3700345945214000726">"काट्नुहोस्"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"फोन राख्नुहोस्"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"आगमन कल"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"भइरहेको कल"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 816ddd4..2e4578c 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -29,5 +29,8 @@
<color name="resolver_empty_state_text">#FFFFFF</color>
<color name="resolver_empty_state_icon">#FFFFFF</color>
+ <color name="call_notification_decline_color">#E66A5E</color>
+ <color name="call_notification_answer_color">#5DBA80</color>
+
<color name="personal_apps_suspension_notification_color">#8AB4F8</color>
</resources>
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..2a619e1 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -87,7 +87,7 @@
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్వర్క్ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్లు చేయలేరు"</string>
- <string name="notification_channel_network_alert" msgid="4788053066033851841">"హెచ్చరికలు"</string>
+ <string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్లు"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్బ్యాక్ మోడ్"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్థితి"</string>
@@ -287,7 +287,7 @@
<string name="notification_channel_network_available" msgid="6083697929214165169">"నెట్వర్క్ అందుబాటులో ఉంది"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్థితి"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"మీ IT నిర్వాహకుల నుండి వచ్చే హెచ్చరికలు"</string>
- <string name="notification_channel_alerts" msgid="5070241039583668427">"హెచ్చరికలు"</string>
+ <string name="notification_channel_alerts" msgid="5070241039583668427">"అలర్ట్లు"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"రిటైల్ డెమో"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"USB కనెక్షన్"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"యాప్ అమలవుతోంది"</string>
@@ -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..5cd3138 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -657,12 +657,26 @@
<!-- 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
display is powered on at the same time. -->
<bool name="config_supportsConcurrentInternalDisplays">true</bool>
+ <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
+ "key:value", for example: "0:1".
+ The keys are device states, and the values are one of
+ Settings.Secure.DeviceStateRotationLockSetting.
+ Any device state that doesn't have a default set here will be treated as
+ DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
+ If this map is missing, the feature is disabled and only one global rotation lock setting
+ will apply, regardless of device state. -->
+ <string-array name="config_perDeviceStateRotationLockDefaults" />
+
+
<!-- Desk dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a desk dock.
@@ -3740,6 +3754,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
@@ -5077,4 +5092,86 @@
<!-- Whether this device should support taking app snapshots on closure -->
<bool name="config_disableTaskSnapshots">false</bool>
+
+ <!-- The display cutout configs for secondary built-in display. -->
+ <string name="config_secondaryBuiltInDisplayCutout" translatable="false"></string>
+ <string name="config_secondaryBuiltInDisplayCutoutRectApproximation" translatable="false">
+ @string/config_secondaryBuiltInDisplayCutout
+ </string>
+ <bool name="config_fillSecondaryBuiltInDisplayCutout">false</bool>
+ <bool name="config_maskSecondaryBuiltInDisplayCutout">false</bool>
+
+ <!-- An array contains unique ids of all built-in displays and the unique id of a display can be
+ obtained from {@link Display#getUniqueId}. This array should be set for multi-display
+ devices if there are different display related configs(e.g. display cutout, rounded corner)
+ between each built-in display.
+ It is used as an index for multi-display related configs:
+ First look up the index of the unique id of the given built-in display unique id in this
+ array and use this index to get the info in corresponding config arrays such as:
+ - config_displayCutoutPathArray
+ - config_displayCutoutApproximationRectArray
+ - config_fillBuiltInDisplayCutoutArray
+ - config_maskBuiltInDisplayCutoutArray
+ - config_waterfallCutoutArray
+
+ Leave this array empty for single display device and the system will load the default main
+ built-in related configs.
+ -->
+ <string-array name="config_displayUniqueIdArray" translatable="false">
+ <!-- Example:
+ <item>"local:1234567891"</item> // main built-in display
+ <item>"local:1234567892"</item> // secondary built-in display
+ -->
+ </string-array>
+
+ <!-- The display cutout path config for each display in a multi-display device. -->
+ <string-array name="config_displayCutoutPathArray" translatable="false">
+ <item>@string/config_mainBuiltInDisplayCutout</item>
+ <item>@string/config_secondaryBuiltInDisplayCutout</item>
+ </string-array>
+
+ <!-- The display cutout approximation rect config for each display in a multi-display device.
+ -->
+ <string-array name="config_displayCutoutApproximationRectArray" translatable="false">
+ <item>@string/config_mainBuiltInDisplayCutoutRectApproximation</item>
+ <item>@string/config_secondaryBuiltInDisplayCutoutRectApproximation</item>
+ </string-array>
+
+ <!-- The maskBuiltInDisplayCutout config for each display in a multi-display device. -->
+ <array name="config_maskBuiltInDisplayCutoutArray" translatable="false">
+ <item>@bool/config_maskMainBuiltInDisplayCutout</item>
+ <item>@bool/config_maskSecondaryBuiltInDisplayCutout</item>
+ </array>
+
+ <!-- The fillBuiltInDisplayCutout config for each display in a multi-display device. -->
+ <array name="config_fillBuiltInDisplayCutoutArray" translatable="false">
+ <item>@bool/config_fillMainBuiltInDisplayCutout</item>
+ <item>@bool/config_fillSecondaryBuiltInDisplayCutout</item>
+ </array>
+
+ <array name="config_mainBuiltInDisplayWaterfallCutout" translatable="false">
+ <item>@dimen/waterfall_display_left_edge_size</item>
+ <item>@dimen/waterfall_display_top_edge_size</item>
+ <item>@dimen/waterfall_display_right_edge_size</item>
+ <item>@dimen/waterfall_display_bottom_edge_size</item>
+ </array>
+
+ <array name="config_secondaryBuiltInDisplayWaterfallCutout" translatable="false">
+ <item>@dimen/secondary_waterfall_display_left_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_top_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_right_edge_size</item>
+ <item>@dimen/secondary_waterfall_display_bottom_edge_size</item>
+ </array>
+
+ <!-- The waterfall cutout config for each display in a multi-display device. -->
+ <array name="config_waterfallCutoutArray" translatable="false">
+ <item>@array/config_mainBuiltInDisplayWaterfallCutout</item>
+ <item>@array/config_secondaryBuiltInDisplayWaterfallCutout</item>
+ </array>
+
+ <!-- Whether the airplane mode should be reset when device boots in non-safemode after exiting
+ from safemode.
+ This flag should be enabled only when the product does not have any UI to toggle airplane
+ mode like automotive devices.-->
+ <bool name="config_autoResetAirplaneMode">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index de7a117..7be9c7b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -920,7 +920,7 @@
<dimen name="chooser_action_button_icon_size">18dp</dimen>
- <!-- For Waterfall Display -->
+ <!-- For main built-in Waterfall Display -->
<dimen name="waterfall_display_left_edge_size">0px</dimen>
<dimen name="waterfall_display_top_edge_size">0px</dimen>
<dimen name="waterfall_display_right_edge_size">0px</dimen>
@@ -943,4 +943,10 @@
<dimen name="starting_surface_icon_size">160dp</dimen>
<!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
<dimen name="starting_surface_default_icon_size">108dp</dimen>
+
+ <!-- For secondary built-in Waterfall Display -->
+ <dimen name="secondary_waterfall_display_left_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_top_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_right_edge_size">0px</dimen>
+ <dimen name="secondary_waterfall_display_bottom_edge_size">0px</dimen>
</resources>
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..8f5cf8a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2218,6 +2218,7 @@
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
+ <java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -3838,6 +3839,9 @@
<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_perDeviceStateRotationLockDefaults" />
+
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
@@ -4442,4 +4446,21 @@
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
<java-symbol type="bool" name="config_disableTaskSnapshots" />
+
+ <java-symbol type="string" name="config_secondaryBuiltInDisplayCutout" />
+ <java-symbol type="string" name="config_secondaryBuiltInDisplayCutoutRectApproximation" />
+ <java-symbol type="bool" name="config_fillSecondaryBuiltInDisplayCutout" />
+ <java-symbol type="bool" name="config_maskSecondaryBuiltInDisplayCutout" />
+ <java-symbol type="array" name="config_displayUniqueIdArray" />
+ <java-symbol type="array" name="config_displayCutoutPathArray" />
+ <java-symbol type="array" name="config_displayCutoutApproximationRectArray" />
+ <java-symbol type="array" name="config_fillBuiltInDisplayCutoutArray" />
+ <java-symbol type="array" name="config_maskBuiltInDisplayCutoutArray" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_left_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_top_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_right_edge_size" />
+ <java-symbol type="dimen" name="secondary_waterfall_display_bottom_edge_size" />
+ <java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
+ <java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
+ <java-symbol type="array" name="config_waterfallCutoutArray" />
</resources>
diff --git a/core/res/res/xml/config_user_types.xml b/core/res/res/xml/config_user_types.xml
index 71dfc55..7663150 100644
--- a/core/res/res/xml/config_user_types.xml
+++ b/core/res/res/xml/config_user_types.xml
@@ -62,6 +62,10 @@
<default-restrictions no_sms="true" no_outgoing_calls="true" />
</profile-type>
+ <full-type
+ name="android.os.usertype.full.RESTRICTED"
+ enabled='0' />
+
<profile-type
name="com.example.profilename"
max-allowed-per-parent="2" />
@@ -78,6 +82,7 @@
Supported optional properties (to be used as shown in the example above) are as follows.
For profile and full users:
default-restrictions (with values defined in UserRestrictionUtils.USER_RESTRICTIONS)
+ enabled
For profile users only:
max-allowed-per-parent
icon-badge
@@ -98,6 +103,9 @@
Note, however, that default-restrictions refers to the restrictions applied at the time of user
creation; therefore, the active restrictions of any pre-existing users will not be updated.
+If a user type is disabled, by setting enabled='0', then no further users of that type may be
+created; however, any pre-existing users of that type will remain.
+
The 'change-user-type' tag should be used in conjunction with the 'version' property of
'user-types'. It defines a type change for all pre-existing users of 'from' type to the new 'to'
type, if the former 'user-type's version of device is less than or equal to 'whenVersionLeq'.
diff --git a/core/tests/BroadcastRadioTests/OWNERS b/core/tests/BroadcastRadioTests/OWNERS
index ea4421e..3e360e7 100644
--- a/core/tests/BroadcastRadioTests/OWNERS
+++ b/core/tests/BroadcastRadioTests/OWNERS
@@ -1,2 +1,3 @@
+keunyoung@google.com
+oscarazu@google.com
twasilczyk@google.com
-randolphs@google.com
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 7c6271c..c194989 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -65,6 +65,7 @@
@Mock ITunerSession mHalTunerSessionMock;
private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
+ private final Object mLock = new Object();
// RadioModule under test
private RadioModule mRadioModule;
@@ -96,7 +97,7 @@
mRadioModule = new RadioModule(mBroadcastRadioMock, new RadioManager.ModuleProperties(0, "",
0, "", "", "", "", 0, 0, false, false, null, false, new int[] {}, new int[] {},
- null, null));
+ null, null), mLock);
doAnswer((Answer) invocation -> {
mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
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/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/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 6301f32..507638e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -698,15 +698,15 @@
@Test
public void testRequestedState() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- final InsetsState state = mTestHost.getRequestedState();
+ final InsetsVisibilities request = mTestHost.getRequestedVisibilities();
mController.hide(statusBars() | navigationBars());
- assertFalse(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR));
- assertFalse(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
+ assertFalse(request.getVisibility(ITYPE_STATUS_BAR));
+ assertFalse(request.getVisibility(ITYPE_NAVIGATION_BAR));
mController.show(statusBars() | navigationBars());
- assertTrue(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR));
- assertTrue(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
+ assertTrue(request.getVisibility(ITYPE_STATUS_BAR));
+ assertTrue(request.getVisibility(ITYPE_NAVIGATION_BAR));
});
}
@@ -837,20 +837,20 @@
public static class TestHost extends ViewRootInsetsControllerHost {
- private final InsetsState mRequestedState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
TestHost(ViewRootImpl viewRoot) {
super(viewRoot);
}
@Override
- public void onInsetsModified(InsetsState insetsState) {
- mRequestedState.set(insetsState, true);
- super.onInsetsModified(insetsState);
+ public void updateRequestedVisibilities(InsetsVisibilities visibilities) {
+ mRequestedVisibilities.set(visibilities);
+ super.updateRequestedVisibilities(visibilities);
}
- public InsetsState getRequestedState() {
- return mRequestedState;
+ public InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
}
}
diff --git a/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java b/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
new file mode 100644
index 0000000..5664e0b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import static android.view.InsetsState.FIRST_TYPE;
+import static android.view.InsetsState.LAST_TYPE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.InsetsState.InternalInsetsType;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link InsetsVisibilities}.
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:InsetsVisibilities
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class InsetsVisibilitiesTest {
+
+ @Test
+ public void testEquals() {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+ final InsetsVisibilities v3 = new InsetsVisibilities();
+ assertEquals(v1, v2);
+ assertEquals(v1, v3);
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, false);
+ v2.setVisibility(type, false);
+ }
+ assertEquals(v1, v2);
+ assertNotEquals(v1, v3);
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, true);
+ v2.setVisibility(type, true);
+ }
+ assertEquals(v1, v2);
+ assertNotEquals(v1, v3);
+ }
+
+ @Test
+ public void testSet() {
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+
+ v1.setVisibility(type, true);
+ assertNotEquals(v1, v2);
+
+ v2.set(v1);
+ assertEquals(v1, v2);
+
+ v2.setVisibility(type, false);
+ assertNotEquals(v1, v2);
+
+ v1.set(v2);
+ assertEquals(v1, v2);
+ }
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ v1.setVisibility(type, true);
+ final InsetsVisibilities v2 = new InsetsVisibilities(v1);
+ assertEquals(v1, v2);
+
+ v2.setVisibility(type, false);
+ assertNotEquals(v1, v2);
+ }
+ }
+
+ @Test
+ public void testGetterAndSetter() {
+ final InsetsVisibilities v1 = new InsetsVisibilities();
+ final InsetsVisibilities v2 = new InsetsVisibilities();
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ assertEquals(InsetsState.getDefaultVisibility(type), v1.getVisibility(type));
+ }
+
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ v1.setVisibility(type, true);
+ assertTrue(v1.getVisibility(type));
+
+ v2.setVisibility(type, false);
+ assertFalse(v2.getVisibility(type));
+ }
+ }
+}
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 65df390..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)
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..cb6e88b 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;
@@ -295,9 +295,8 @@
}
@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();
@@ -333,9 +332,8 @@
}
@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 +377,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 +395,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 +428,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 +454,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 +478,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 +502,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 +587,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 +601,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/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/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index b59b84bb..63e13fd 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -186,7 +186,6 @@
sPerProcStateTimesAvailable = fgCpuTimes != null;
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testCpuFreqTimes() throws Exception {
if (!sCpuFreqTimesAvailable) {
@@ -215,7 +214,6 @@
batteryOffScreenOn();
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testCpuFreqTimes_screenOff() throws Exception {
if (!sCpuFreqTimesAvailable) {
@@ -278,7 +276,6 @@
batteryOffScreenOn();
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testCpuFreqTimes_stateTop() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -312,7 +309,6 @@
batteryOffScreenOn();
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testIsolatedCpuFreqTimes_stateService() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -354,7 +350,6 @@
batteryOffScreenOn();
}
- @SkipPresubmit("b/185960974 flaky")
@Test
public void testCpuFreqTimes_stateTopSleeping() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -389,7 +384,6 @@
}
@Test
- @SkipPresubmit("b/183225190 flaky")
public void testCpuFreqTimes_stateFgService() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -455,7 +449,6 @@
batteryOff();
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testCpuFreqTimes_stateBg() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -522,7 +515,6 @@
batteryOffScreenOn();
}
- @SkipPresubmit("b/184201598 flaky")
@Test
public void testCpuFreqTimes_trackingDisabled() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
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 d9b69b1..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() {
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/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
new file mode 100644
index 0000000..d800c2c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.nio.file.Files;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ProcLocksReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
+ @Test
+ public void testRunSimpleLocks() throws Exception {
+ String simpleLocks =
+ "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n";
+ assertFalse(runHasFileLocks(simpleLocks, 18402));
+ assertFalse(runHasFileLocks(simpleLocks, 18404));
+ assertTrue(runHasFileLocks(simpleLocks, 18403));
+ assertTrue(runHasFileLocks(simpleLocks, 18292));
+ }
+
+ @Test
+ public void testRunBlockedLocks() throws Exception {
+ String blockedLocks =
+ "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n" +
+ "2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n" +
+ "2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n" +
+ "3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n" +
+ "4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335\n";
+ assertFalse(runHasFileLocks(blockedLocks, 18402));
+ assertFalse(runHasFileLocks(blockedLocks, 18404));
+ assertTrue(runHasFileLocks(blockedLocks, 18403));
+ assertTrue(runHasFileLocks(blockedLocks, 18292));
+
+ assertFalse(runHasFileLocks(blockedLocks, 18291));
+ assertFalse(runHasFileLocks(blockedLocks, 18293));
+ assertTrue(runHasFileLocks(blockedLocks, 3888));
+ }
+
+ private boolean runHasFileLocks(String fileContents, int pid) throws Exception {
+ File tempFile = File.createTempFile("locks", null, mProcDirectory);
+ Files.write(tempFile.toPath(), fileContents.getBytes());
+ boolean result = new ProcLocksReader(tempFile.toString()).hasFileLocks(pid);
+ Files.delete(tempFile.toPath());
+ return result;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 7d4412c..0f05be0 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -24,7 +24,7 @@
import android.os.Parcel;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -60,7 +60,7 @@
new Binder() /* imeToken */,
true /* navbarColorManagedByIme */,
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- new InsetsState() /* requestedState */,
+ new InsetsVisibilities() /* requestedVisibilities */,
"test" /* packageName */,
new int[0] /* transientBarTypes */);
@@ -81,7 +81,7 @@
assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken);
assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
assertThat(copy.mBehavior).isEqualTo(original.mBehavior);
- assertThat(copy.mRequestedState).isEqualTo(original.mRequestedState);
+ assertThat(copy.mRequestedVisibilities).isEqualTo(original.mRequestedVisibilities);
assertThat(copy.mPackageName).isEqualTo(original.mPackageName);
assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes);
}
diff --git a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
index b6da195..0532628 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
@@ -166,6 +166,46 @@
assertEquals(-1L, reader.nextOptionalLong(-1L));
}
+ public void testInvalidLongs() throws Exception {
+ final ProcFileReader reader = buildReader("12: 34\n56 78@#\n");
+
+ assertEquals(12L, reader.nextLong(true));
+ assertEquals(34L, reader.nextLong(true));
+ reader.finishLine();
+ assertTrue(reader.hasMoreData());
+
+ assertEquals(56L, reader.nextLong(true));
+ assertEquals(78L, reader.nextLong(true));
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
+ public void testConsecutiveDelimiters() throws Exception {
+ final ProcFileReader reader = buildReader("1 2 3 4 5\n");
+
+ assertEquals(1L, reader.nextLong());
+ assertEquals(2L, reader.nextLong());
+ assertEquals(3L, reader.nextLong());
+ assertEquals(4L, reader.nextLong());
+ assertEquals(5L, reader.nextLong());
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
+ public void testIgnore() throws Exception {
+ final ProcFileReader reader = buildReader("a b c\n");
+
+ assertEquals("a", reader.nextString());
+ assertTrue(reader.hasMoreData());
+
+ reader.nextIgnored();
+ assertTrue(reader.hasMoreData());
+
+ assertEquals("c", reader.nextString());
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
private static ProcFileReader buildReader(String string) throws IOException {
return buildReader(string, 2048);
}
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/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 74fb618..4925209 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -53,6 +53,7 @@
private long mStartTime;
private boolean mForceSoftware;
private Animator mLoopAnimation;
+ private Animator mCurrentAnimation;
RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
boolean forceSoftware) {
@@ -74,6 +75,12 @@
return this;
}
+ void end() {
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.end();
+ }
+ }
+
@NonNull RippleAnimationSession exit(Canvas canvas) {
if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas);
else exitSoftware();
@@ -114,10 +121,12 @@
if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
+ if (mCurrentAnimation == expand) mCurrentAnimation = null;
}
});
expand.setInterpolator(LINEAR_INTERPOLATOR);
expand.start();
+ mCurrentAnimation = expand;
}
private long computeDelay() {
@@ -147,6 +156,7 @@
if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
+ if (mCurrentAnimation == exit) mCurrentAnimation = null;
}
});
exit.setTarget(canvas);
@@ -155,6 +165,7 @@
long delay = computeDelay();
exit.setStartDelay(delay);
exit.start();
+ mCurrentAnimation = exit;
}
private void enterHardware(RecordingCanvas canvas) {
@@ -167,6 +178,7 @@
mStartTime + MAX_NOISE_PHASE);
loop.setTarget(canvas);
startAnimation(expand, loop);
+ mCurrentAnimation = expand;
}
private void startAnimation(Animator expand, Animator loop) {
@@ -200,6 +212,7 @@
mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
});
startAnimation(expand, loop);
+ mCurrentAnimation = expand;
}
void setRadius(float radius) {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index b994ad2..d3cff5c 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -278,6 +278,15 @@
}
cancelExitingRipples();
+ endPatternedAnimations();
+ }
+
+ private void endPatternedAnimations() {
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ RippleAnimationSession session = mRunningAnimations.get(i);
+ session.end();
+ }
+ mRunningAnimations.clear();
}
private void cancelExitingRipples() {
@@ -291,7 +300,6 @@
Arrays.fill(ripples, 0, count, null);
}
mExitingRipplesCount = 0;
- mExitingAnimation = true;
// Always draw an additional "clean" frame after canceling animations.
invalidateSelf(false);
}
@@ -714,7 +722,7 @@
}
cancelExitingRipples();
- exitPatternedAnimation();
+ endPatternedAnimations();
}
@Override
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/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 48d78cf..0f2f23e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -116,6 +116,9 @@
secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent,
activityOptions);
+ // Set adjacent to each other so that the containers below will be invisible.
+ wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken);
+
applyTransaction(wct);
}
@@ -126,6 +129,7 @@
*/
void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
resizeTaskFragment(wct, fragmentToken, new Rect());
+ wct.setAdjacentTaskFragments(fragmentToken, null);
}
/**
@@ -175,7 +179,8 @@
final TaskFragmentCreationParams fragmentOptions =
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
wct.createTaskFragment(fragmentOptions)
- .startActivityInTaskFragment(fragmentToken, activityIntent, activityOptions);
+ .startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
+ activityOptions);
}
TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
@@ -186,7 +191,7 @@
}
return new TaskFragmentCreationParams.Builder(
- getIOrganizer(),
+ getOrganizerToken(),
fragmentToken,
ownerToken)
.setInitialBounds(bounds)
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 7298d34..407c43d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -26,7 +26,9 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -40,6 +42,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Main controller class that manages split states and presentation.
@@ -57,8 +60,7 @@
private SplitOrganizerCallback mSplitOrganizerCallback;
public SplitController() {
- mPresenter = new SplitPresenter(ActivityThread.currentActivityThread().getExecutor(),
- this);
+ mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
// Register a callback to be notified about activities being created.
ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
new LifecycleCallbacks());
@@ -99,39 +101,38 @@
@Override
public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(
- taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken())) {
- container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
- return;
- }
+ TaskFragmentContainer container = getContainer(
+ taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken());
+ if (container == null) {
+ return;
}
+
+ container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
}
@Override
public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
- container.setInfo(taskFragmentInfo);
+ TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
+ if (container == null) {
+ return;
+ }
- if (taskFragmentInfo.isEmpty()) {
- cleanupContainer(container, true /* shouldFinishDependent */);
- updateCallbackIfNecessary();
- }
- return;
- }
+ container.setInfo(taskFragmentInfo);
+ if (taskFragmentInfo.isEmpty()) {
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
}
}
@Override
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
- for (TaskFragmentContainer container : mContainers) {
- if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
- cleanupContainer(container, true /* shouldFinishDependent */);
- updateCallbackIfNecessary();
- return;
- }
+ TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
+ if (container == null) {
+ return;
}
+
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
}
@Override
@@ -148,6 +149,7 @@
* 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.
*/
+ // TODO(b/190433398): Break down into smaller functions.
void onActivityCreated(@NonNull Activity launchedActivity) {
final ComponentName componentName = launchedActivity.getComponentName();
@@ -201,6 +203,18 @@
return;
}
+ // Check if the split is already set.
+ final TaskFragmentContainer activityBelowContainer = getContainerWithActivity(
+ activityBelow.getActivityToken());
+ if (currentContainer != null && activityBelowContainer != null) {
+ final SplitContainer existingSplit = getActiveSplitForContainers(currentContainer,
+ activityBelowContainer);
+ if (existingSplit != null) {
+ // There is already an active split with the activity below.
+ return;
+ }
+ }
+
final ExtensionSplitPairRule splitPairRule = getSplitRule(
activityBelow.getComponentName(), componentName, splitRules);
if (splitPairRule == null) {
@@ -213,6 +227,20 @@
updateCallbackIfNecessary();
}
+ private void onActivityConfigurationChanged(@NonNull Activity activity) {
+ final TaskFragmentContainer currentContainer = getContainerWithActivity(
+ activity.getActivityToken());
+
+ if (currentContainer != null) {
+ // Changes to activities in controllers are handled in
+ // onTaskFragmentParentInfoChanged
+ return;
+ }
+
+ // Check if activity requires a placeholder
+ launchPlaceholderIfNecessary(activity);
+ }
+
/**
* Returns a container that this activity is registered with. An activity can only belong to one
* container, or no container at all.
@@ -324,7 +352,7 @@
}
/**
- * Returns the top active split container that has the provided container.
+ * Returns the top active split container that has the provided container, if available.
*/
@Nullable
private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
@@ -339,6 +367,26 @@
}
/**
+ * Returns the active split that has the provided containers as primary and secondary or as
+ * secondary and primary, if available.
+ */
+ @Nullable
+ private SplitContainer getActiveSplitForContainers(
+ @NonNull TaskFragmentContainer firstContainer,
+ @NonNull TaskFragmentContainer secondContainer) {
+ for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+ SplitContainer splitContainer = mSplitContainers.get(i);
+ final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
+ final TaskFragmentContainer secondary = splitContainer.getSecondaryContainer();
+ if ((firstContainer == secondary && secondContainer == primary)
+ || (firstContainer == primary && secondContainer == secondary)) {
+ return splitContainer;
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks if the container requires a placeholder and launches it if necessary.
*/
private boolean launchPlaceholderIfNecessary(@NonNull TaskFragmentContainer container) {
@@ -480,7 +528,7 @@
}
@Nullable
- private TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
+ TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
for (TaskFragmentContainer container : mContainers) {
if (container.getTaskFragmentToken().equals(fragmentToken)) {
return container;
@@ -546,6 +594,10 @@
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onActivityPostCreated(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
@@ -576,5 +628,20 @@
@Override
public void onActivityDestroyed(Activity activity) {
}
+
+ @Override
+ public void onActivityConfigurationChanged(Activity activity) {
+ SplitController.this.onActivityConfigurationChanged(activity);
+ }
+ }
+
+ /** Executor that posts on the main application thread. */
+ private static class MainThreadExecutor implements Executor {
+ private final Handler handler = new Handler(Looper.getMainLooper());
+
+ @Override
+ public void execute(Runnable r) {
+ handler.post(r);
+ }
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
index 381d6d7..7ad83aa 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -23,6 +23,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.IBinder;
import android.window.TaskFragmentCreationParams;
import android.window.WindowContainerTransaction;
@@ -98,8 +99,6 @@
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) {
@@ -115,10 +114,13 @@
wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
primaryActivity.getActivityToken());
+
+ primaryContainer.setLastRequestedBounds(primaryRectBounds);
} else {
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
}
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
secondaryActivity.getActivityToken());
if (secondaryContainer == null || secondaryContainer == primaryContainer) {
@@ -134,12 +136,15 @@
wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
secondaryActivity.getActivityToken());
+
+ secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
} 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.
+ // Set adjacent to each other so that the containers below will be invisible.
+ wct.setAdjacentTaskFragments(
+ primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
applyTransaction(wct);
mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -177,8 +182,8 @@
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.
+ primaryContainer.setLastRequestedBounds(primaryRectBounds);
+ secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
mController.registerSplit(primaryContainer, launchingActivity, secondaryContainer,
rule);
@@ -199,7 +204,6 @@
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(),
@@ -219,10 +223,27 @@
if (container.getInfo() == null) {
return;
}
- // TODO(b/190433398): Check if the bounds actually changed.
resizeTaskFragment(wct, container.getTaskFragmentToken(), bounds);
}
+ @Override
+ void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+ @Nullable Rect bounds) {
+ TaskFragmentContainer container = mController.getContainer(fragmentToken);
+ if (container == null) {
+ throw new IllegalStateException(
+ "Resizing a task fragment that is not registered with controller.");
+ }
+
+ if (container.areLastRequestedBoundsEqual(bounds)) {
+ // Return early if the provided bounds were already requested
+ return;
+ }
+
+ container.setLastRequestedBounds(bounds);
+ super.resizeTaskFragment(wct, fragmentToken, bounds);
+ }
+
boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
return shouldShowSideBySide(parentBounds, splitContainer.getSplitPairRule());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
index 3cf37a6..368adef 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.window.TaskFragmentInfo;
@@ -60,6 +61,11 @@
private boolean mIsFinished;
/**
+ * Bounds that were requested last via {@link android.window.WindowContainerTransaction}.
+ */
+ private final Rect mLastRequestedBounds = new Rect();
+
+ /**
* Creates a container with an existing activity that will be re-parented to it in a window
* container transaction.
*/
@@ -199,4 +205,23 @@
boolean isFinished() {
return mIsFinished;
}
+
+ /**
+ * Checks if last requested bounds are equal to the provided value.
+ */
+ boolean areLastRequestedBoundsEqual(@Nullable Rect bounds) {
+ return (bounds == null && mLastRequestedBounds.isEmpty())
+ || mLastRequestedBounds.equals(bounds);
+ }
+
+ /**
+ * Updates the last requested bounds.
+ */
+ void setLastRequestedBounds(@Nullable Rect bounds) {
+ if (bounds == null) {
+ mLastRequestedBounds.setEmpty();
+ } else {
+ mLastRequestedBounds.set(bounds);
+ }
+ }
}
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/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index c09ae53..b333e33 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -22,7 +22,6 @@
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="8dp"
- android:layout_marginLeft="16dp"
android:layout_marginBottom="8dp"
android:focusable="true"
android:text="@string/manage_bubbles_text"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index f4b3aca..298ad30 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -25,15 +25,15 @@
android:id="@+id/bubble_manage_menu_dismiss_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/ic_remove_no_shadow"
android:tint="@color/bubbles_icon_tint"/>
@@ -50,15 +50,15 @@
android:id="@+id/bubble_manage_menu_dont_bubble_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/bubble_ic_stop_bubble"
android:tint="@color/bubbles_icon_tint"/>
@@ -75,16 +75,16 @@
android:id="@+id/bubble_manage_menu_settings_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
android:id="@+id/bubble_manage_menu_settings_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/ic_remove_no_shadow"/>
<TextView
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/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index c16041d..8056d15 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -46,7 +46,7 @@
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Үстүнкү экранды 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ылдыйкы экранды толук экран режимине өткөрүү"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бир кол режимин колдонуу"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө көздөй сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бир кол режимин баштоо"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Бир кол режиминен чыгуу"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index f28ee82..07bb890 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -152,6 +152,10 @@
<dimen name="bubble_manage_button_height">56dp</dimen>
<!-- Height of an item in the bubble manage menu. -->
<dimen name="bubble_menu_item_height">60dp</dimen>
+ <!-- Padding applied to the bubble manage menu. -->
+ <dimen name="bubble_menu_padding">16dp</dimen>
+ <!-- Size of the icons in the manage menu. -->
+ <dimen name="bubble_menu_icon_size">24dp</dimen>
<!-- Max width of the message bubble-->
<dimen name="bubble_message_max_width">144dp</dimen>
<!-- Min width of the message bubble -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 94a8758..8405385 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -215,7 +215,7 @@
if (mSplitLayout != null) {
if (mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
}
// updateConfiguration re-inits the dividerbar, so show it now
mSyncQueue.runInSync(t -> t.show(mSplitLayout.getDividerLeash()));
@@ -299,17 +299,24 @@
}
@Override
- public void onBoundsChanging(SplitLayout layout) {
+ public void onLayoutChanging(SplitLayout layout) {
mSyncQueue.runInSync(t ->
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
@Override
- public void onBoundsChanged(SplitLayout layout) {
+ public void onLayoutChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t ->
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
+
+ @Override
+ public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
+ mController.getTaskOrganizer().applyTransaction(wct);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 28e2f7dd..e7764ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -56,7 +56,6 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -98,7 +97,6 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -581,7 +579,7 @@
/**
* BubbleStackView is lazily created by this method the first time a Bubble is added. This
- * method initializes the stack view and adds it to the StatusBar just above the scrim.
+ * method initializes the stack view and adds it to window manager.
*/
private void ensureStackViewCreated() {
if (mStackView == null) {
@@ -629,7 +627,6 @@
try {
mAddedToWindowManager = true;
mBubbleData.getOverflow().initialize(this);
- mStackView.addView(mBubbleScrim);
mWindowManager.addView(mStackView, mWmLayoutParams);
// Position info is dependent on us being attached to a window
mBubblePositioner.update();
@@ -661,7 +658,6 @@
mAddedToWindowManager = false;
if (mStackView != null) {
mWindowManager.removeView(mStackView);
- mStackView.removeView(mBubbleScrim);
mBubbleData.getOverflow().cleanUpExpandedState();
} else {
Log.w(TAG, "StackView added to WindowManager, but was null when removing!");
@@ -763,13 +759,6 @@
}
}
- private void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
- mBubbleScrim = view;
- callback.accept(mMainExecutor, mMainExecutor.executeBlockingForResult(() -> {
- return Looper.myLooper();
- }, Looper.class));
- }
-
private void setSysuiProxy(Bubbles.SysuiProxy proxy) {
mSysuiProxy = proxy;
}
@@ -1574,13 +1563,6 @@
}
@Override
- public void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
- mMainExecutor.execute(() -> {
- BubbleController.this.setBubbleScrim(view, callback);
- });
- }
-
- @Override
public void setExpandListener(BubbleExpandListener listener) {
mMainExecutor.execute(() -> {
BubbleController.this.setExpandListener(listener);
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..126d735 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
@@ -19,6 +19,8 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -33,11 +35,11 @@
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -45,6 +47,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;
@@ -105,9 +108,6 @@
*/
private static final float FLYOUT_OVERSCROLL_ATTENUATION_FACTOR = 8f;
- /** Duration of the flyout alpha animations. */
- private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100;
-
private static final int FADE_IN_DURATION = 320;
/** Percent to darken the bubbles when they're in the dismiss target. */
@@ -121,6 +121,10 @@
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
+ private static final int MANAGE_MENU_SCRIM_ANIM_DURATION = 150;
+
+ private static final float SCRIM_ALPHA = 0.6f;
+
/**
* How long to wait to animate the stack temporarily invisible after a drag/flyout hide
* animation ends, if we are in fact temporarily invisible.
@@ -194,7 +198,8 @@
private StackAnimationController mStackAnimationController;
private ExpandedAnimationController mExpandedAnimationController;
- private View mTaskbarScrim;
+ private View mScrim;
+ private View mManageMenuScrim;
private FrameLayout mExpandedViewContainer;
/** Matrix used to scale the expanded view container with a given pivot point. */
@@ -205,6 +210,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 +814,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(
@@ -842,11 +862,20 @@
mBubbleData.setExpanded(true);
});
- mTaskbarScrim = new View(getContext());
- mTaskbarScrim.setBackgroundColor(Color.BLACK);
- addView(mTaskbarScrim);
- mTaskbarScrim.setAlpha(0f);
- mTaskbarScrim.setVisibility(GONE);
+ mScrim = new View(getContext());
+ mScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
+ addView(mScrim);
+ mScrim.setAlpha(0f);
+
+ mManageMenuScrim = new View(getContext());
+ mManageMenuScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
+ addView(mManageMenuScrim, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mManageMenuScrim.setAlpha(0f);
+ mManageMenuScrim.setVisibility(INVISIBLE);
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
@@ -1204,6 +1233,10 @@
updateOverflow();
updateUserEdu();
updateExpandedViewTheme();
+ mScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
+ mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
}
/**
@@ -1783,6 +1816,20 @@
mExpandedViewAlphaAnimator.start();
}
+ private void showScrim(boolean show) {
+ if (show) {
+ mScrim.animate()
+ .setInterpolator(ALPHA_IN)
+ .alpha(SCRIM_ALPHA)
+ .start();
+ } else {
+ mScrim.animate()
+ .alpha(0f)
+ .setInterpolator(ALPHA_OUT)
+ .start();
+ }
+ }
+
private void animateExpansion() {
cancelDelayedExpandCollapseSwitchAnimations();
final boolean showVertically = mPositioner.showBubblesVertically();
@@ -1792,6 +1839,7 @@
}
beforeExpandedViewAnimation();
+ showScrim(true);
updateZOrder();
updateBadges(false /* setBadgeForCollapsedStack */);
mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -1803,16 +1851,6 @@
}
} /* after */);
- if (mPositioner.showingInTaskbar()
- // Don't need the scrim when the bar is at the bottom
- && mPositioner.getTaskbarPosition() != BubblePositioner.TASKBAR_POSITION_BOTTOM) {
- mTaskbarScrim.getLayoutParams().width = mPositioner.getTaskbarSize();
- mTaskbarScrim.setTranslationX(mStackOnLeftOrWillBe
- ? 0f
- : mPositioner.getAvailableRect().right - mPositioner.getTaskbarSize());
- mTaskbarScrim.setVisibility(VISIBLE);
- mTaskbarScrim.animate().alpha(1f).start();
- }
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
getBubbleIndex(mExpandedBubble));
mExpandedViewContainer.setTranslationX(0f);
@@ -1923,6 +1961,8 @@
mIsExpanded = false;
mIsExpansionAnimating = true;
+ showScrim(false);
+
mBubbleContainer.cancelAllAnimations();
// If we were in the middle of swapping, the animating-out surface would have been scaling
@@ -1940,10 +1980,6 @@
/* collapseTo */,
() -> mBubbleContainer.setActiveController(mStackAnimationController));
- if (mTaskbarScrim.getVisibility() == VISIBLE) {
- mTaskbarScrim.animate().alpha(0f).start();
- }
-
int index;
if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
index = mBubbleData.getBubbles().size();
@@ -2011,10 +2047,6 @@
if (previouslySelected != null) {
previouslySelected.setTaskViewVisibility(false);
}
-
- if (mPositioner.showingInTaskbar()) {
- mTaskbarScrim.setVisibility(GONE);
- }
})
.start();
}
@@ -2489,6 +2521,24 @@
return;
}
+ if (show) {
+ mManageMenuScrim.setVisibility(VISIBLE);
+ mManageMenuScrim.setTranslationZ(mManageMenu.getElevation() - 1f);
+ }
+ Runnable endAction = () -> {
+ if (!show) {
+ mManageMenuScrim.setVisibility(INVISIBLE);
+ mManageMenuScrim.setTranslationZ(0f);
+ }
+ };
+
+ mManageMenuScrim.animate()
+ .setDuration(MANAGE_MENU_SCRIM_ANIM_DURATION)
+ .setInterpolator(show ? ALPHA_IN : ALPHA_OUT)
+ .alpha(show ? SCRIM_ALPHA : 0f)
+ .withEndAction(endAction)
+ .start();
+
// If available, update the manage menu's settings option with the expanded bubble's app
// name and icon.
if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {
@@ -2652,7 +2702,7 @@
return;
}
- if (!mIsExpanded) {
+ if (!mIsExpanded || !mAnimatingOutSurfaceReady) {
onComplete.accept(false);
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index c73b5ee..9b7eb2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -24,12 +24,10 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.os.Looper;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.SparseArray;
-import android.view.View;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -43,7 +41,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -160,14 +157,6 @@
/** Set the proxy to commnuicate with SysUi side components. */
void setSysuiProxy(SysuiProxy proxy);
- /**
- * Set the scrim view for bubbles.
- *
- * @param callback The callback made with the executor and the executor's looper that the view
- * will be running on.
- **/
- void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback);
-
/** Set a listener to be notified of bubble expand events. */
void setExpandListener(BubbleExpandListener listener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 6f63369..ba59e07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -33,6 +33,7 @@
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -198,6 +199,7 @@
public class PerDisplay {
final int mDisplayId;
final InsetsState mInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
new DisplayWindowInsetsControllerImpl();
InsetsSourceControl mImeSourceControl = null;
@@ -327,8 +329,10 @@
*/
private void setVisibleDirectly(boolean visible) {
mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ mRequestedVisibilities.setVisibility(InsetsState.ITYPE_IME, visible);
try {
- mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ mWmService.updateDisplayWindowRequestedVisibilities(mDisplayId,
+ mRequestedVisibilities);
} catch (RemoteException e) {
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 8adfac0..b9ccd69 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.common.split;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_TOP;
@@ -224,13 +226,13 @@
void updateDivideBounds(int position) {
updateBounds(position);
mSplitWindowManager.setResizingSplits(true);
- mSplitLayoutHandler.onBoundsChanging(this);
+ mSplitLayoutHandler.onLayoutChanging(this);
}
void setDividePosition(int position) {
mDividePosition = position;
updateBounds(mDividePosition);
- mSplitLayoutHandler.onBoundsChanged(this);
+ mSplitLayoutHandler.onLayoutChanged(this);
mSplitWindowManager.setResizingSplits(false);
}
@@ -352,6 +354,46 @@
.setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
}
+ /**
+ * Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
+ * restore shifted configuration bounds if it's no longer shifted.
+ */
+ public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY,
+ ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
+ if (offsetX == 0 && offsetY == 0) {
+ wct.setBounds(taskInfo1.token, mBounds1);
+ wct.setAppBounds(taskInfo1.token, null);
+ wct.setScreenSizeDp(taskInfo1.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+
+ wct.setBounds(taskInfo2.token, mBounds2);
+ wct.setAppBounds(taskInfo2.token, null);
+ wct.setScreenSizeDp(taskInfo2.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+ } else {
+ final Rect bounds = new Rect();
+ bounds.set(taskInfo1.configuration.windowConfiguration.getBounds());
+ bounds.offset(offsetX, offsetY);
+ wct.setBounds(taskInfo1.token, bounds);
+ bounds.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
+ bounds.offset(offsetX, offsetY);
+ wct.setAppBounds(taskInfo1.token, bounds);
+ wct.setScreenSizeDp(taskInfo1.token,
+ taskInfo1.configuration.screenWidthDp,
+ taskInfo1.configuration.screenHeightDp);
+
+ bounds.set(taskInfo2.configuration.windowConfiguration.getBounds());
+ bounds.offset(offsetX, offsetY);
+ wct.setBounds(taskInfo2.token, bounds);
+ bounds.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
+ bounds.offset(offsetX, offsetY);
+ wct.setAppBounds(taskInfo2.token, bounds);
+ wct.setScreenSizeDp(taskInfo2.token,
+ taskInfo2.configuration.screenWidthDp,
+ taskInfo2.configuration.screenHeightDp);
+ }
+ }
+
/** Handles layout change event. */
public interface SplitLayoutHandler {
@@ -359,10 +401,18 @@
void onSnappedToDismiss(boolean snappedToEnd);
/** Calls when the bounds is changing due to animation or dragging divider bar. */
- void onBoundsChanging(SplitLayout layout);
+ void onLayoutChanging(SplitLayout layout);
/** Calls when the target bounds changed. */
- void onBoundsChanged(SplitLayout layout);
+ void onLayoutChanged(SplitLayout layout);
+
+ /**
+ * Notifies when the layout shifted. So the layout handler can shift configuration
+ * bounds correspondingly to make sure client apps won't get configuration changed or
+ * relaunch. If the layout is no longer shifted, layout handler should restore shifted
+ * configuration bounds.
+ */
+ void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout);
/** Calls when user double tapped on the divider bar. */
default void onDoubleTappedDivider() {
@@ -427,6 +477,18 @@
&& !isFloating && !isLandscape(mRootBounds) && showing;
mTargetYOffset = needOffset ? getTargetYOffset() : 0;
+ if (mTargetYOffset != mLastYOffset) {
+ // Freeze the configuration size with offset to prevent app get a configuration
+ // changed or relaunch. This is required to make sure client apps will calculate
+ // insets properly after layout shifted.
+ if (mTargetYOffset == 0) {
+ mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this);
+ } else {
+ mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset,
+ SplitLayout.this);
+ }
+ }
+
// Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
// ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
// because DividerView won't receive onImeVisibilityChanged callback after it being
@@ -441,7 +503,7 @@
public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
if (displayId != mDisplayId) return;
onProgress(getProgress(imeTop));
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
@Override
@@ -449,7 +511,7 @@
SurfaceControl.Transaction t) {
if (displayId != mDisplayId || cancel) return;
onProgress(1.0f);
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
@Override
@@ -459,7 +521,7 @@
if (!controlling && mImeShown) {
reset();
mSplitWindowManager.setInteractive(true);
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 9bcc3ac..5b9d7b80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -151,10 +151,8 @@
final Rect rightHitRegion = new Rect();
final Rect rightDrawRegion = bottomOrRightBounds;
- displayRegion.splitVertically(leftHitRegion, fullscreenHitRegion, rightHitRegion);
+ displayRegion.splitVertically(leftHitRegion, rightHitRegion);
- mTargets.add(
- new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, leftDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, rightDrawRegion));
@@ -165,10 +163,8 @@
final Rect bottomDrawRegion = bottomOrRightBounds;
displayRegion.splitHorizontally(
- topHitRegion, fullscreenHitRegion, bottomHitRegion);
+ topHitRegion, bottomHitRegion);
- mTargets.add(
- new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topDrawRegion));
mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomDrawRegion));
}
@@ -269,7 +265,6 @@
* Updates the session data based on the current state of the system.
*/
void update() {
-
List<ActivityManager.RunningTaskInfo> tasks =
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
if (!tasks.isEmpty()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java
index 24e5111..8969cc8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java
@@ -46,7 +46,7 @@
/**
* Called when OneHanded animator is updating position
*/
- default void onAnimationUpdate(float xPos, float yPos) {
+ default void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) {
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
index bfb2cc6..4b78328 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
@@ -182,10 +182,10 @@
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
- applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());
mOneHandedAnimationCallbacks.forEach(
- (callback) -> callback.onAnimationUpdate(0f, mCurrentValue)
+ (callback) -> callback.onAnimationUpdate(tx, 0f, mCurrentValue)
);
+ applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());
}
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
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..97461e6 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
@@ -16,13 +16,14 @@
package com.android.wm.shell.onehanded;
+import android.animation.ValueAnimator;
import android.content.Context;
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.view.animation.LinearInterpolator;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
@@ -30,9 +31,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.core.content.ContextCompat;
+import androidx.appcompat.view.ContextThemeWrapper;
-import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
@@ -46,169 +46,212 @@
* the screen has entered one handed mode.
*/
public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
- implements OneHandedTransitionCallback {
+ implements OneHandedAnimationCallback {
private static final String TAG = "OneHandedBackgroundPanelOrganizer";
+ private static final int THEME_COLOR_OFFSET = 10;
+ private static final int ALPHA_ANIMATION_DURATION = 200;
- private final Object mLock = new Object();
+ private final Context mContext;
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final float[] mDefaultColor;
- private final Executor mMainExecutor;
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
- mSurfaceControlTransactionFactory;
+ mTransactionFactory;
+
+ private ValueAnimator mAlphaAnimator;
+
+ private float mTranslationFraction;
+ private float[] mThemeColor;
/**
* The background to distinguish the boundary of translated windows and empty region when
* one handed mode triggered.
*/
private Rect mBkgBounds;
+ private Rect mStableInsets;
+
+ @Nullable
@VisibleForTesting
- @GuardedBy("mLock")
- boolean mIsShowing;
+ SurfaceControl mBackgroundSurface;
@Nullable
- @GuardedBy("mLock")
- private SurfaceControl mBackgroundSurface;
- @Nullable
- @GuardedBy("mLock")
private SurfaceControl mParentLeash;
- private final OneHandedAnimationCallback mOneHandedAnimationCallback =
- new OneHandedAnimationCallback() {
- @Override
- public void onOneHandedAnimationStart(
- OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mMainExecutor.execute(() -> showBackgroundPanelLayer());
- }
- };
-
- @Override
- public void onStopFinished(Rect bounds) {
- mMainExecutor.execute(() -> removeBackgroundPanelLayer());
- }
-
public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout,
- Executor executor) {
+ OneHandedSettingsUtil settingsUtil, Executor executor) {
super(executor);
- // 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};
- mMainExecutor = executor;
- mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mContext = context;
+ mTranslationFraction = settingsUtil.getTranslationFraction(context);
+ mTransactionFactory = SurfaceControl.Transaction::new;
+ updateThemeColors();
}
@Override
public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
@NonNull SurfaceControl leash) {
- synchronized (mLock) {
- if (mParentLeash == null) {
- mParentLeash = leash;
- } else {
- throw new RuntimeException("There should be only one DisplayArea for "
- + "the one-handed mode background panel");
- }
- }
- }
-
- OneHandedAnimationCallback getOneHandedAnimationCallback() {
- return mOneHandedAnimationCallback;
+ mParentLeash = leash;
}
@Override
public List<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
- synchronized (mLock) {
- final List<DisplayAreaAppearedInfo> displayAreaInfos;
- displayAreaInfos = super.registerOrganizer(displayAreaFeature);
- for (int i = 0; i < displayAreaInfos.size(); i++) {
- final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
- onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
- }
- return displayAreaInfos;
+ final List<DisplayAreaAppearedInfo> displayAreaInfos;
+ displayAreaInfos = super.registerOrganizer(displayAreaFeature);
+ for (int i = 0; i < displayAreaInfos.size(); i++) {
+ final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
+ onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
}
+ return displayAreaInfos;
}
@Override
public void unregisterOrganizer() {
- synchronized (mLock) {
- super.unregisterOrganizer();
- mParentLeash = null;
- }
+ super.unregisterOrganizer();
+ removeBackgroundPanelLayer();
+ mParentLeash = null;
+ }
+
+ @Override
+ public void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) {
+ final int yTopPos = (mStableInsets.top - mBkgBounds.height()) + Math.round(yPos);
+ tx.setPosition(mBackgroundSurface, 0, yTopPos);
}
@Nullable
@VisibleForTesting
- SurfaceControl getBackgroundSurface() {
- synchronized (mLock) {
- if (mParentLeash == null) {
- return null;
- }
+ boolean isRegistered() {
+ return mParentLeash != null;
+ }
- if (mBackgroundSurface == null) {
- mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession)
- .setParent(mParentLeash)
- .setBufferSize(mBkgBounds.width(), mBkgBounds.height())
- .setColorLayer()
- .setFormat(PixelFormat.RGB_888)
- .setOpaque(true)
- .setName("one-handed-background-panel")
- .setCallsite("OneHandedBackgroundPanelOrganizer")
- .build();
- }
- return mBackgroundSurface;
+ void createBackgroundSurface() {
+ mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession)
+ .setBufferSize(mBkgBounds.width(), mBkgBounds.height())
+ .setColorLayer()
+ .setFormat(PixelFormat.RGB_888)
+ .setOpaque(true)
+ .setName("one-handed-background-panel")
+ .setCallsite("OneHandedBackgroundPanelOrganizer")
+ .build();
+
+ // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
+ mAlphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
+ mAlphaAnimator.setInterpolator(new LinearInterpolator());
+ mAlphaAnimator.setDuration(ALPHA_ANIMATION_DURATION);
+ mAlphaAnimator.addUpdateListener(
+ animator -> detachBackgroundFromParent(animator));
+ }
+
+ void detachBackgroundFromParent(ValueAnimator animator) {
+ if (mBackgroundSurface == null || mParentLeash == null) {
+ return;
}
+ // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
+ final float currentValue = (float) animator.getAnimatedValue();
+ final SurfaceControl.Transaction tx = mTransactionFactory.getTransaction();
+ if (currentValue == 0.0f) {
+ tx.reparent(mBackgroundSurface, null).apply();
+ } else {
+ tx.setAlpha(mBackgroundSurface, (float) animator.getAnimatedValue()).apply();
+ }
+ }
+
+ /**
+ * Called when onDisplayAdded() or onDisplayRemoved() callback.
+ *
+ * @param displayLayout The latest {@link DisplayLayout} representing current displayId
+ */
+ public void onDisplayChanged(DisplayLayout displayLayout) {
+ mStableInsets = displayLayout.stableInsets();
+ // Ensure the mBkgBounds is portrait, due to OHM only support on portrait
+ if (displayLayout.height() > displayLayout.width()) {
+ mBkgBounds = new Rect(0, 0, displayLayout.width(),
+ Math.round(displayLayout.height() * mTranslationFraction) + mStableInsets.top);
+ } else {
+ mBkgBounds = new Rect(0, 0, displayLayout.height(),
+ Math.round(displayLayout.width() * mTranslationFraction) + mStableInsets.top);
+ }
+ }
+
+ @VisibleForTesting
+ void onStart() {
+ if (mBackgroundSurface == null) {
+ createBackgroundSurface();
+ }
+ showBackgroundPanelLayer();
+ }
+
+ /**
+ * Called when transition finished.
+ */
+ public void onStopFinished() {
+ mAlphaAnimator.start();
}
@VisibleForTesting
void showBackgroundPanelLayer() {
- synchronized (mLock) {
- if (mIsShowing) {
- return;
- }
-
- if (getBackgroundSurface() == null) {
- Log.w(TAG, "mBackgroundSurface is null !");
- return;
- }
-
- SurfaceControl.Transaction transaction =
- mSurfaceControlTransactionFactory.getTransaction();
- transaction.setLayer(mBackgroundSurface, -1 /* at bottom-most layer */)
- .setColor(mBackgroundSurface, mDefaultColor)
- .show(mBackgroundSurface)
- .apply();
- transaction.close();
- mIsShowing = true;
+ if (mParentLeash == null) {
+ return;
}
+
+ if (mBackgroundSurface == null) {
+ createBackgroundSurface();
+ }
+
+ // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
+ if (mAlphaAnimator.isRunning()) {
+ mAlphaAnimator.end();
+ }
+
+ mTransactionFactory.getTransaction()
+ .reparent(mBackgroundSurface, mParentLeash)
+ .setAlpha(mBackgroundSurface, 1.0f)
+ .setLayer(mBackgroundSurface, -1 /* at bottom-most layer */)
+ .setColor(mBackgroundSurface, mThemeColor)
+ .show(mBackgroundSurface)
+ .apply();
}
@VisibleForTesting
void removeBackgroundPanelLayer() {
- synchronized (mLock) {
- if (mBackgroundSurface == null) {
- return;
- }
-
- SurfaceControl.Transaction transaction =
- mSurfaceControlTransactionFactory.getTransaction();
- transaction.remove(mBackgroundSurface).apply();
- transaction.close();
- mBackgroundSurface = null;
- mIsShowing = false;
+ if (mBackgroundSurface == null) {
+ return;
}
+
+ mTransactionFactory.getTransaction()
+ .remove(mBackgroundSurface)
+ .apply();
+ mBackgroundSurface = null;
+ }
+
+ /**
+ * onConfigurationChanged events for updating tutorial text.
+ */
+ public void onConfigurationChanged() {
+ updateThemeColors();
+ showBackgroundPanelLayer();
+ }
+
+ private void updateThemeColors() {
+ final Context themedContext = new ContextThemeWrapper(mContext,
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ final int themeColor = themedContext.getColor(
+ R.color.one_handed_tutorial_background_color);
+ mThemeColor = new float[]{
+ adjustColor(Color.red(themeColor)),
+ adjustColor(Color.green(themeColor)),
+ adjustColor(Color.blue(themeColor))};
+ }
+
+ private float adjustColor(int origColor) {
+ return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f;
}
void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
- pw.print(innerPrefix + "mIsShowing=");
- pw.println(mIsShowing);
+ pw.print(innerPrefix + "mBackgroundSurface=");
+ pw.println(mBackgroundSurface);
pw.print(innerPrefix + "mBkgBounds=");
pw.println(mBkgBounds);
- pw.print(innerPrefix + "mDefaultColor=");
- pw.println(mDefaultColor);
+ pw.print(innerPrefix + "mThemeColor=");
+ pw.println(mThemeColor);
+ pw.print(innerPrefix + "mTranslationFraction=");
+ pw.println(mTranslationFraction);
}
}
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..b0fe856 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
@@ -180,6 +180,7 @@
public void onStopFinished(Rect bounds) {
mState.setState(STATE_NONE);
notifyShortcutStateChanged(STATE_NONE);
+ mBackgroundPanelOrganizer.onStopFinished();
}
};
@@ -223,13 +224,14 @@
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
OneHandedState transitionState = new OneHandedState();
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
- windowManager);
+ settingsUtil, windowManager);
OneHandedAnimationController animationController =
new OneHandedAnimationController(context);
OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
mainExecutor);
OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
- new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor);
+ new OneHandedBackgroundPanelOrganizer(context, displayLayout, settingsUtil,
+ mainExecutor);
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
context, displayLayout, settingsUtil, animationController, tutorialHandler,
oneHandedBackgroundPanelOrganizer, mainExecutor);
@@ -386,6 +388,7 @@
mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
mOneHandedAccessibilityUtil.announcementForScreenReader(
mOneHandedAccessibilityUtil.getOneHandedStartDescription());
+ mBackgroundPanelOrganizer.onStart();
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
mTimeoutHandler.resetTimer();
mOneHandedUiEventLogger.writeEvent(
@@ -423,7 +426,6 @@
stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT));
mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
- mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer);
mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallBack);
if (mTaskChangeToExit) {
mTaskStackListener.addListener(mTaskStackListenerCallback);
@@ -469,6 +471,7 @@
final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId);
mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
mTutorialHandler.onDisplayChanged(newDisplayLayout);
+ mBackgroundPanelOrganizer.onDisplayChanged(newDisplayLayout);
}
private ContentObserver getObserver(Runnable onChangeRunnable) {
@@ -606,7 +609,7 @@
OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
}
- if (mBackgroundPanelOrganizer.getBackgroundSurface() == null) {
+ if (!mBackgroundPanelOrganizer.isRegistered()) {
mBackgroundPanelOrganizer.registerOrganizer(
OneHandedBackgroundPanelOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL);
}
@@ -658,12 +661,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/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 03a90c6..c2bbd9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -135,8 +135,8 @@
SystemProperties.getInt(ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION,
animationDurationConfig);
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mTutorialHandler = tutorialHandler;
mBackgroundPanelOrganizer = oneHandedBackgroundGradientOrganizer;
+ mTutorialHandler = tutorialHandler;
}
@Override
@@ -249,9 +249,8 @@
if (animator != null) {
animator.setTransitionDirection(direction)
.addOneHandedAnimationCallback(mOneHandedAnimationCallback)
- .addOneHandedAnimationCallback(mTutorialHandler.getAnimationCallback())
- .addOneHandedAnimationCallback(
- mBackgroundPanelOrganizer.getOneHandedAnimationCallback())
+ .addOneHandedAnimationCallback(mTutorialHandler)
+ .addOneHandedAnimationCallback(mBackgroundPanelOrganizer)
.setDuration(durationMs)
.start();
}
@@ -267,7 +266,6 @@
mLastVisualDisplayBounds.offsetTo(0, Math.round(mLastVisualOffset));
for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
final OneHandedTransitionCallback cb = mTransitionCallbacks.get(i);
- cb.onStartTransition(false /* isTransitioning */);
if (direction == TRANSITION_DIRECTION_TRIGGER) {
cb.onStartFinished(getLastVisualDisplayBounds());
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index aa6961a..21bc889 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.content.ContentResolver;
+import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.Settings;
@@ -27,6 +28,8 @@
import androidx.annotation.Nullable;
+import com.android.wm.shell.R;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,7 +39,6 @@
*/
public final class OneHandedSettingsUtil {
private static final String TAG = "OneHandedSettingsUtil";
-
private static final String ONE_HANDED_MODE_TARGET_NAME =
ONE_HANDED_COMPONENT_NAME.getShortClassName();
@@ -217,6 +219,25 @@
Settings.Secure.ONE_HANDED_MODE_ACTIVATED, state, userId);
}
+ /**
+ * Obtains one-handed mode transition duration from resource config.
+ *
+ * @return durationMs The duration in milli-seconds
+ */
+ public int getTransitionDuration(Context context) {
+ return context.getResources().getInteger(
+ R.integer.config_one_handed_translate_animation_duration);
+ }
+
+ /**
+ * Obtains one-handed mode offset fraction from resource config.
+ *
+ * @return fraction The fraction of offset of the whole screen.
+ */
+ public float getTranslationFraction(Context context) {
+ return context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1);
+ }
+
void dump(PrintWriter pw, String prefix, ContentResolver resolver,
int userId) {
final String innerPrefix = " ";
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..88f3375 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,17 +25,25 @@
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;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.SurfaceControl;
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;
@@ -51,10 +59,9 @@
* detach TargetViewContainer from window after exiting one handed mode.
*/
public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
- OneHandedState.OnStateChangedListener {
+ OneHandedState.OnStateChangedListener, OneHandedAnimationCallback {
private static final String TAG = "OneHandedTutorialHandler";
- private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
- "persist.debug.one_handed_offset_percentage";
+ private static final float START_TRANSITION_FRACTION = 0.6f;
private final float mTutorialHeightRatio;
private final WindowManager mWindowManager;
@@ -64,28 +71,42 @@
private Context mContext;
private Rect mDisplayBounds;
+ private ValueAnimator mAlphaAnimator;
private @Nullable View mTutorialView;
private @Nullable ViewGroup mTargetViewContainer;
- private final OneHandedAnimationCallback mAnimationCallback;
+ private float mAlphaTransitionStart;
+ private int mAlphaAnimationDurationMs;
- public OneHandedTutorialHandler(Context context, WindowManager windowManager) {
+ public OneHandedTutorialHandler(Context context, OneHandedSettingsUtil settingsUtil,
+ WindowManager windowManager) {
mContext = context;
mWindowManager = windowManager;
- 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));
- mTutorialHeightRatio = sysPropPercentageConfig / 100.0f;
- mAnimationCallback = new OneHandedAnimationCallback() {
- @Override
- public void onAnimationUpdate(float xPos, float yPos) {
- if (!isAttached()) {
- return;
- }
- mTargetViewContainer.setTranslationY(yPos - mTutorialAreaHeight);
- }
- };
+ mTutorialHeightRatio = settingsUtil.getTranslationFraction(context);
+ mAlphaAnimationDurationMs = settingsUtil.getTransitionDuration(context);
+ }
+
+ @Override
+ public void onOneHandedAnimationCancel(
+ OneHandedAnimationController.OneHandedTransitionAnimator animator) {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ }
+
+ @Override
+ public void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) {
+ if (!isAttached()) {
+ return;
+ }
+ if (yPos < mAlphaTransitionStart) {
+ checkTransitionEnd();
+ return;
+ }
+ if (mAlphaAnimator == null || mAlphaAnimator.isStarted() || mAlphaAnimator.isRunning()) {
+ return;
+ }
+ mAlphaAnimator.start();
}
@Override
@@ -94,12 +115,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:
@@ -109,6 +134,7 @@
/**
* Called when onDisplayAdded() or onDisplayRemoved() callback.
+ *
* @param displayLayout The latest {@link DisplayLayout} representing current displayId
*/
public void onDisplayChanged(DisplayLayout displayLayout) {
@@ -119,6 +145,7 @@
mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
}
mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
+ mAlphaTransitionStart = mTutorialAreaHeight * START_TRANSITION_FRACTION;
}
@VisibleForTesting
@@ -129,6 +156,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);
@@ -158,10 +186,6 @@
mTargetViewContainer = null;
}
- @Nullable OneHandedAnimationCallback getAnimationCallback() {
- return mAnimationCallback;
- }
-
/**
* Returns layout params for the dismiss target, using the latest display metrics.
*/
@@ -192,6 +216,54 @@
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;
+ final int duration = isEntering ? mAlphaAnimationDurationMs : Math.round(
+ mAlphaAnimationDurationMs * (1.0f - mTutorialHeightRatio));
+ mAlphaAnimator = ValueAnimator.ofFloat(start, end);
+ mAlphaAnimator.setInterpolator(new LinearInterpolator());
+ mAlphaAnimator.setDuration(duration);
+ mAlphaAnimator.addUpdateListener(
+ animator -> mTargetViewContainer.setAlpha((float) animator.getAnimatedValue()));
+ }
+
+ private void checkTransitionEnd() {
+ if (mAlphaAnimator != null && (mAlphaAnimator.isRunning() || mAlphaAnimator.isStarted())) {
+ mAlphaAnimator.end();
+ mAlphaAnimator.removeAllUpdateListeners();
+ mAlphaAnimator = null;
}
}
@@ -206,5 +278,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 200af74..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
@@ -38,6 +38,7 @@
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;
@@ -617,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 a0d83c0..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
@@ -243,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;
@@ -343,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();
@@ -356,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;
}
@@ -517,7 +509,7 @@
mOnDisplayIdChangeCallback.accept(info.displayId);
}
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
} else {
@@ -626,7 +618,7 @@
private void onEndOfSwipePipToHomeTransition() {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
return;
}
@@ -650,7 +642,7 @@
null /* callback */, false /* withStartDelay */);
}
}, tx);
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
}
@@ -718,7 +710,7 @@
return;
}
clearWaitForFixedRotation();
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mPictureInPictureParams = null;
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
// Re-set the PIP bounds to none.
@@ -793,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.
@@ -859,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());
}
@@ -1383,11 +1377,20 @@
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
@@ -1400,6 +1403,10 @@
}
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);
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/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index d6afeba..e86462f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -17,10 +17,13 @@
package com.android.wm.shell.splitscreen;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
+import java.util.concurrent.Executor;
+
/**
* Interface to engage split-screen feature.
* TODO: Figure out which of these are actually needed outside of the Shell
@@ -53,10 +56,18 @@
/** Callback interface for listening to changes in a split-screen stage. */
interface SplitScreenListener {
- void onStagePositionChanged(@StageType int stage, @SplitPosition int position);
- void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
+ default void onStagePositionChanged(@StageType int stage, @SplitPosition int position) {}
+ default void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {}
+ default void onSplitVisibilityChanged(boolean visible) {}
}
+ /** Registers listener that gets split screen callback. */
+ void registerSplitScreenListener(@NonNull SplitScreenListener listener,
+ @NonNull Executor executor);
+
+ /** Unregisters listener that gets split screen callback. */
+ void unregisterSplitScreenListener(@NonNull SplitScreenListener listener);
+
/**
* Returns a binder that can be passed to an external process to manipulate SplitScreen.
*/
@@ -70,6 +81,12 @@
*/
void onKeyguardOccludedChanged(boolean occluded);
+ /**
+ * Called when the visibility of the keyguard changes.
+ * @param showing Indicates if the keyguard is now visible.
+ */
+ void onKeyguardVisibilityChanged(boolean showing);
+
/** Get a string representation of a stage type */
static String stageTypeToString(@StageType int stage) {
switch (stage) {
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..7804c77 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
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Slog;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationAdapter;
@@ -64,6 +65,7 @@
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
/**
* Class manages split-screen multitasking mode and implements the main interface
@@ -170,6 +172,10 @@
mStageCoordinator.onKeyguardOccludedChanged(occluded);
}
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mStageCoordinator.onKeyguardVisibilityChanged(showing);
+ }
+
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
}
@@ -249,14 +255,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 {
@@ -290,6 +299,38 @@
@ExternalThread
private class SplitScreenImpl implements SplitScreen {
private ISplitScreenImpl mISplitScreen;
+ private final ArrayMap<SplitScreenListener, Executor> mExecutors = new ArrayMap<>();
+ private final SplitScreen.SplitScreenListener mListener = new SplitScreenListener() {
+ @Override
+ public void onStagePositionChanged(int stage, int position) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onStagePositionChanged(stage, position);
+ });
+ }
+ }
+
+ @Override
+ public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onTaskStageChanged(taskId, stage, visible);
+ });
+ }
+ }
+
+ @Override
+ public void onSplitVisibilityChanged(boolean visible) {
+ for (int i = 0; i < mExecutors.size(); i++) {
+ final int index = i;
+ mExecutors.valueAt(index).execute(() -> {
+ mExecutors.keyAt(index).onSplitVisibilityChanged(visible);
+ });
+ }
+ }
+ };
@Override
public ISplitScreen createExternalInterface() {
@@ -306,6 +347,41 @@
SplitScreenController.this.onKeyguardOccludedChanged(occluded);
});
}
+
+ @Override
+ public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
+ if (mExecutors.containsKey(listener)) return;
+
+ mMainExecutor.execute(() -> {
+ if (mExecutors.size() == 0) {
+ SplitScreenController.this.registerSplitScreenListener(mListener);
+ }
+
+ mExecutors.put(listener, executor);
+ });
+
+ executor.execute(() -> {
+ mStageCoordinator.sendStatusToListener(listener);
+ });
+ }
+
+ @Override
+ public void unregisterSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ mExecutors.remove(listener);
+
+ if (mExecutors.size() == 0) {
+ SplitScreenController.this.unregisterSplitScreenListener(mListener);
+ }
+ });
+ }
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.onKeyguardVisibilityChanged(showing);
+ });
+ }
}
/**
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..29e9917 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
@@ -136,7 +136,10 @@
/** Whether the device is supporting legacy split or not. */
private boolean mUseLegacySplit;
- @SplitScreen.StageType int mDismissTop = NO_DISMISS;
+ @SplitScreen.StageType private int mDismissTop = NO_DISMISS;
+
+ /** The target stage to dismiss to when unlock after folded. */
+ @SplitScreen.StageType private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
private final Runnable mOnTransitionAnimationComplete = () -> {
// If still playing, let it finish.
@@ -422,7 +425,7 @@
if (mSideStageListener.mVisible && updateBounds) {
if (wct == null) {
// onBoundsChanged builds/applies a wct with the contents of updateWindowBounds.
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
} else {
updateWindowBounds(mSplitLayout, wct);
}
@@ -443,6 +446,13 @@
mKeyguardOccluded = occluded;
}
+ void onKeyguardVisibilityChanged(boolean showing) {
+ if (!showing && mMainStage.isActive()
+ && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage);
+ }
+ }
+
void exitSplitScreen() {
exitSplitScreen(null /* childrenToTop */);
}
@@ -458,6 +468,7 @@
mTaskOrganizer.applyTransaction(wct);
// Reset divider position.
mSplitLayout.resetDividerPosition();
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
/**
@@ -501,16 +512,21 @@
void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
if (mListeners.contains(listener)) return;
mListeners.add(listener);
- listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
- listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
- mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
- mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ sendStatusToListener(listener);
}
void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
mListeners.remove(listener);
}
+ void sendStatusToListener(SplitScreen.SplitScreenListener listener) {
+ listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition());
+ listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition());
+ listener.onSplitVisibilityChanged(isSplitScreenVisible());
+ mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
+ mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+ }
+
private void sendOnStagePositionChanged() {
for (int i = mListeners.size() - 1; i >= 0; --i) {
final SplitScreen.SplitScreenListener l = mListeners.get(i);
@@ -535,6 +551,13 @@
}
}
+ private void sendSplitVisibilityChanged() {
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ final SplitScreen.SplitScreenListener l = mListeners.get(i);
+ l.onSplitVisibilityChanged(mDividerVisible);
+ }
+ }
+
private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
mUseLegacySplit = mContext.getResources().getBoolean(R.bool.config_useLegacySplit);
@@ -574,6 +597,7 @@
} else {
mSplitLayout.release();
}
+ sendSplitVisibilityChanged();
}
private void onStageVisibilityChanged(StageListenerImpl stageListener) {
@@ -620,22 +644,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 +673,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;
@@ -711,12 +743,12 @@
}
@Override
- public void onBoundsChanging(SplitLayout layout) {
+ public void onLayoutChanging(SplitLayout layout) {
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
}
@Override
- public void onBoundsChanged(SplitLayout layout) {
+ public void onLayoutChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
mSyncQueue.queue(wct);
@@ -760,6 +792,18 @@
}
@Override
+ public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ final StageTaskListener topLeftStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ final StageTaskListener bottomRightStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
+ bottomRightStage.mRootTaskInfo);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
+ @Override
public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
mDisplayAreaInfo = displayAreaInfo;
if (mSplitLayout == null) {
@@ -781,13 +825,19 @@
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
+ mSyncQueue.runInSync(t -> applyDividerVisibility(t));
}
}
private void onFoldedStateChanged(boolean folded) {
- if (folded && mMainStage.isActive()) {
- exitSplitScreen(mMainStage);
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ if (!folded) return;
+
+ if (mMainStage.isFocused()) {
+ mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
+ } else if (mSideStage.isFocused()) {
+ mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
}
@@ -1075,7 +1125,7 @@
null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
new android.graphics.Point(0, 0) /* position */, bounds, bounds,
new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
- null /* taskInfo */, TYPE_DOCK_DIVIDER);
+ null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 4f73fee..c47353a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -97,6 +97,15 @@
return mChildrenTaskInfo.contains(taskId);
}
+ /** @return {@code true} if this listener contains the currently focused task. */
+ boolean isFocused() {
+ if (mRootTaskInfo.isFocused) return true;
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ if (mChildrenTaskInfo.valueAt(i).isFocused) return true;
+ }
+ return false;
+ }
+
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
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..29326ec 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,7 +23,9 @@
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import android.annotation.ColorInt;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -37,6 +39,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 +60,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 +135,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 +211,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();
@@ -312,7 +316,7 @@
private Drawable mOverlayDrawable;
private int mSuggestType;
private int mThemeColor;
- private Drawable mFinalIconDrawable;
+ private Drawable[] mFinalIconDrawables;
private int mFinalIconSize = mIconSize;
StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
@@ -344,12 +348,13 @@
animationDuration = 0;
mFinalIconSize = 0;
} else if (mTmpAttrs.mSplashScreenIcon != null) {
- // replaced icon, don't process
+ // Using the windowSplashScreenAnimatedIcon attribute
iconDrawable = mTmpAttrs.mSplashScreenIcon;
animationDuration = mTmpAttrs.mAnimationDuration;
// There is no background below the icon, so scale the icon up
- if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT) {
+ if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT
+ || mTmpAttrs.mIconBgColor == mThemeColor) {
mFinalIconSize *= NO_BACKGROUND_SCALE;
}
createIconDrawable(iconDrawable, false);
@@ -368,25 +373,34 @@
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;
}
- return fillViewWithIcon(mFinalIconSize, mFinalIconDrawable, animationDuration);
+ return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, 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,
+ mFinalIconDrawables = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
} else {
- mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
- mTmpAttrs.mIconBgColor != Color.TRANSPARENT
- ? mTmpAttrs.mIconBgColor : mThemeColor,
+ mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable(
+ mTmpAttrs.mIconBgColor, mThemeColor,
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
}
}
@@ -402,7 +416,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 +446,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.
@@ -447,18 +462,24 @@
return true;
}
- private SplashScreenView fillViewWithIcon(int iconSize, Drawable iconDrawable,
+ private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable,
int animationDuration) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
- final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext);
- builder.setBackgroundColor(mThemeColor);
- builder.setOverlayDrawable(mOverlayDrawable);
+ Drawable foreground = null;
+ Drawable background = null;
if (iconDrawable != null) {
- builder.setIconSize(iconSize)
- .setIconBackground(mTmpAttrs.mIconBgColor)
- .setCenterViewDrawable(iconDrawable)
- .setAnimationDurationMillis(animationDuration);
+ foreground = iconDrawable.length > 0 ? iconDrawable[0] : null;
+ background = iconDrawable.length > 1 ? iconDrawable[1] : null;
}
+
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
+ final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext)
+ .setBackgroundColor(mThemeColor)
+ .setOverlayDrawable(mOverlayDrawable)
+ .setIconSize(iconSize)
+ .setIconBackground(background)
+ .setCenterViewDrawable(foreground)
+ .setAnimationDurationMillis(animationDuration);
+
if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
&& mTmpAttrs.mBrandingImage != null) {
builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth,
@@ -533,13 +554,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 +592,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 +616,7 @@
* A help class to check the color information from a Drawable.
*/
private interface ColorTester {
- float nonTransparentRatio();
+ float passFilterRatio();
boolean isComplexColor();
@@ -610,7 +644,7 @@
}
@Override
- public float nonTransparentRatio() {
+ public float passFilterRatio() {
final int alpha = mColorDrawable.getAlpha();
return (float) (alpha / 255);
}
@@ -639,15 +673,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 +708,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 +723,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 +755,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 +793,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 +856,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 +951,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..951b97e 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
@@ -22,9 +22,11 @@
import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -33,7 +35,6 @@
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Animatable;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Trace;
@@ -44,33 +45,55 @@
/**
* Creating a lightweight Drawable object used for splash screen.
+ *
* @hide
*/
public class SplashscreenIconDrawableFactory {
- static Drawable makeIconDrawable(@ColorInt int backgroundColor,
+ /**
+ * @return An array containing the foreground drawable at index 0 and if needed a background
+ * drawable at index 1.
+ */
+ static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
@NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
Handler splashscreenWorkerHandler) {
+ Drawable foreground;
+ Drawable background = null;
+ boolean drawBackground =
+ backgroundColor != Color.TRANSPARENT && backgroundColor != themeColor;
+
if (foregroundDrawable instanceof Animatable) {
- return new AnimatableIconAnimateListener(backgroundColor, foregroundDrawable);
+ foreground = new AnimatableIconAnimateListener(foregroundDrawable);
} else if (foregroundDrawable instanceof AdaptiveIconDrawable) {
- return new ImmobileIconDrawable(foregroundDrawable,
+ // If the icon is Adaptive, we already use the icon background.
+ drawBackground = false;
+ foreground = new ImmobileIconDrawable(foregroundDrawable,
srcIconSize, iconSize, splashscreenWorkerHandler);
} else {
- // single layer icon
- return new ImmobileIconDrawable(new AdaptiveIconDrawable(
- new ColorDrawable(backgroundColor), foregroundDrawable),
+ // Adaptive icon don't handle transparency so we draw the background of the adaptive
+ // icon with the same color as the window background color instead of using two layers
+ foreground = new ImmobileIconDrawable(
+ new AdaptiveForegroundDrawable(foregroundDrawable),
srcIconSize, iconSize, splashscreenWorkerHandler);
}
+
+ if (drawBackground) {
+ background = new MaskBackgroundDrawable(backgroundColor);
+ }
+
+ return new Drawable[]{foreground, background};
}
- 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 Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
+ splashscreenWorkerHandler)};
}
+ /**
+ * Drawable pre-drawing the scaled icon in a separate thread to increase the speed of the
+ * final drawing.
+ */
private static class ImmobileIconDrawable extends Drawable {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG);
@@ -122,8 +145,10 @@
}
}
- // Base class the draw the circle background
- private abstract static class MaskBackgroundDrawable extends Drawable {
+ /**
+ * Base class the draw a background clipped by the system mask.
+ */
+ public static class MaskBackgroundDrawable extends Drawable {
private static final float MASK_SIZE = AdaptiveIconDrawable.MASK_SIZE;
private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f;
static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
@@ -133,17 +158,24 @@
private static Path sMask;
private final Path mMaskScaleOnly;
private final Matrix mMaskMatrix;
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
- | Paint.FILTER_BITMAP_FLAG);
- MaskBackgroundDrawable(@ColorInt int backgroundColor) {
+ @Nullable
+ private final Paint mBackgroundPaint;
+
+ public MaskBackgroundDrawable(@ColorInt int backgroundColor) {
final Resources r = Resources.getSystem();
sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
Path mask = new Path(sMask);
mMaskScaleOnly = new Path(mask);
mMaskMatrix = new Matrix();
- mPaint.setColor(backgroundColor);
- mPaint.setStyle(Paint.Style.FILL);
+ if (backgroundColor != Color.TRANSPARENT) {
+ mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
+ | Paint.FILTER_BITMAP_FLAG);
+ mBackgroundPaint.setColor(backgroundColor);
+ mBackgroundPaint.setStyle(Paint.Style.FILL);
+ } else {
+ mBackgroundPaint = null;
+ }
}
@Override
@@ -163,99 +195,80 @@
@Override
public void draw(Canvas canvas) {
canvas.clipPath(mMaskScaleOnly);
- if (mMaskScaleOnly != null) {
- canvas.drawPath(mMaskScaleOnly, mPaint);
+ if (mBackgroundPaint != null) {
+ canvas.drawPath(mMaskScaleOnly, mBackgroundPaint);
}
}
@Override
public void setAlpha(int alpha) {
- mPaint.setAlpha(alpha);
+ if (mBackgroundPaint != null) {
+ mBackgroundPaint.setAlpha(alpha);
+ }
}
@Override
public int getOpacity() {
return PixelFormat.RGBA_8888;
}
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
}
- 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;
+ private static class AdaptiveForegroundDrawable extends MaskBackgroundDrawable {
- LegacyIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
- super(backgroundColor);
+ @NonNull
+ protected final Drawable mForegroundDrawable;
+ private final Rect mTmpOutRect = new Rect();
+
+ AdaptiveForegroundDrawable(@NonNull Drawable foregroundDrawable) {
+ super(Color.TRANSPARENT);
mForegroundDrawable = foregroundDrawable;
- mScaleX = LEGACY_ICON_SCALE;
- mScaleY = LEGACY_ICON_SCALE;
}
@Override
protected void updateLayerBounds(Rect bounds) {
super.updateLayerBounds(bounds);
+ int cX = bounds.width() / 2;
+ int cY = bounds.height() / 2;
- if (mForegroundDrawable == null) {
- return;
+ int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
+ final Rect outRect = mTmpOutRect;
+ outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
+ if (mForegroundDrawable != null) {
+ mForegroundDrawable.setBounds(outRect);
}
- 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);
+ mForegroundDrawable.draw(canvas);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setColorFilter(colorFilter);
- }
+ mForegroundDrawable.setColorFilter(colorFilter);
}
}
+
/**
* A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
* drawable masked by config_icon_mask.
*/
- private static class AnimatableIconAnimateListener extends MaskBackgroundDrawable
+ private static class AnimatableIconAnimateListener extends AdaptiveForegroundDrawable
implements SplashScreenView.IconAnimateListener {
- private final Drawable mForegroundDrawable;
private Animatable mAnimatableIcon;
private Animator mIconAnimator;
private boolean mAnimationTriggered;
- private final Rect mTmpOutRect = new Rect();
- AnimatableIconAnimateListener(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
- super(backgroundColor);
- mForegroundDrawable = foregroundDrawable;
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setCallback(mCallback);
- }
+ AnimatableIconAnimateListener(@NonNull Drawable foregroundDrawable) {
+ super(foregroundDrawable);
+ mForegroundDrawable.setCallback(mCallback);
}
@Override
@@ -291,22 +304,6 @@
return true;
}
- @Override
- protected void updateLayerBounds(Rect bounds) {
- super.updateLayerBounds(bounds);
- int cX = bounds.width() / 2;
- int cY = bounds.height() / 2;
-
- int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
- int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
- final Rect outRect = mTmpOutRect;
- outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setBounds(outRect);
- }
- invalidateSelf();
- }
-
private final Callback mCallback = new Callback() {
@Override
public void invalidateDrawable(@NonNull Drawable who) {
@@ -336,19 +333,8 @@
@Override
public void draw(Canvas canvas) {
+ ensureAnimationStarted();
super.draw(canvas);
- if (mForegroundDrawable != null) {
- ensureAnimationStarted();
- mForegroundDrawable.draw(canvas);
- }
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setColorFilter(colorFilter);
- }
}
}
-
}
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/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 6052d3d..7d011e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -72,6 +72,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -205,7 +206,7 @@
final SurfaceControl surfaceControl = new SurfaceControl();
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
- final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
+ final InsetsSourceControl[] tmpControls = new InsetsSourceControl[0];
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
final TaskDescription taskDescription;
@@ -225,13 +226,14 @@
delayRemovalTime, topWindowInsetsState, clearWindowHandler, splashScreenExecutor);
final Window window = snapshotSurface.mWindow;
- final InsetsState mTmpInsetsState = new InsetsState();
+ final InsetsState tmpInsetsState = new InsetsState();
+ final InsetsVisibilities tmpRequestedVisibilities = new InsetsVisibilities();
final InputChannel tmpInputChannel = new InputChannel();
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#addToDisplay");
final int res = session.addToDisplay(window, layoutParams, View.GONE, displayId,
- mTmpInsetsState, tmpInputChannel, mTmpInsetsState, mTempControls);
+ tmpRequestedVisibilities, tmpInputChannel, tmpInsetsState, tmpControls);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
@@ -244,8 +246,8 @@
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
- tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
- mTempControls, TMP_SURFACE_SIZE);
+ tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
+ tmpControls, TMP_SURFACE_SIZE);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 7f42fe9..01134a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -59,6 +59,7 @@
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
@@ -132,6 +133,15 @@
@NonNull Transitions.TransitionFinishCallback finishCallback) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"start default transition animation, info = %s", info);
+
+ // Fallback for screen wake. This just immediately finishes since there is no
+ // animation for screen-wake.
+ if (info.getType() == WindowManager.TRANSIT_WAKE) {
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ return true;
+ }
+
if (mAnimations.containsKey(transition)) {
throw new IllegalStateException("Got a duplicate startAnimation call for "
+ transition);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index f432049..bda884c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -107,6 +107,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Checking filter %s",
mFilters.get(i));
if (mFilters.get(i).first.matches(info)) {
+ Slog.d(TAG, "Found filter" + mFilters.get(i));
pendingRemote = mFilters.get(i).second;
// Add to requested list so that it can be found for merge requests.
mRequestedRemotes.put(transition, pendingRemote);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index e138595..3dc0465 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -92,13 +92,13 @@
@Test
public void testUpdateDivideBounds() {
mSplitLayout.updateDivideBounds(anyInt());
- verify(mSplitLayoutHandler).onBoundsChanging(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class));
}
@Test
public void testSetDividePosition() {
mSplitLayout.setDividePosition(anyInt());
- verify(mSplitLayoutHandler).onBoundsChanged(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index ba73d55..1a70f76 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -25,6 +25,7 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
@@ -210,15 +211,15 @@
}
@Test
- public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets() {
+ public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
@@ -227,15 +228,15 @@
}
@Test
- public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets() {
+ public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
@@ -244,65 +245,55 @@
}
@Test
- public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets() {
- setRunningTask(mNonResizeableFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
- ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- }
-
- @Test
- public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets() {
- setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mNonResizeableActivityClipData);
- ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- }
-
- @Test
- public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() {
+ public void testDragAppOverSplitApp_expectSplitTargets_DropLeft() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- reset(mSplitScreenStarter);
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+ }
- // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ @Test
+ public void testDragAppOverSplitApp_expectSplitTargets_DropRight() {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
- public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets() {
+ public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropTop() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
- reset(mSplitScreenStarter);
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+ }
- // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ @Test
+ public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropBottom() {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
index 3f47c04..99c6107 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
@@ -22,7 +22,10 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -54,17 +57,17 @@
private OneHandedBackgroundPanelOrganizer mSpiedBackgroundPanelOrganizer;
private WindowContainerToken mToken;
private SurfaceControl mLeash;
- private TestableLooper mTestableLooper;
@Mock
IWindowContainerToken mMockRealToken;
@Mock
DisplayController mMockDisplayController;
+ @Mock
+ OneHandedSettingsUtil mMockSettingsUtil;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTestableLooper = TestableLooper.get(this);
mToken = new WindowContainerToken(mMockRealToken);
mLeash = new SurfaceControl();
mDisplay = mContext.getDisplay();
@@ -74,32 +77,36 @@
FEATURE_ONE_HANDED_BACKGROUND_PANEL);
mSpiedBackgroundPanelOrganizer = spy(
- new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, Runnable::run));
+ new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, mMockSettingsUtil,
+ Runnable::run));
+ mSpiedBackgroundPanelOrganizer.onDisplayChanged(mDisplayLayout);
}
@Test
public void testOnDisplayAreaAppeared() {
mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
- mTestableLooper.processAllMessages();
- assertThat(mSpiedBackgroundPanelOrganizer.getBackgroundSurface()).isNotNull();
+ assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isTrue();
+ verify(mSpiedBackgroundPanelOrganizer, never()).showBackgroundPanelLayer();
}
@Test
public void testShowBackgroundLayer() {
- mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
- mSpiedBackgroundPanelOrganizer.showBackgroundPanelLayer();
- mTestableLooper.processAllMessages();
+ mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, null);
+ mSpiedBackgroundPanelOrganizer.onStart();
- assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isTrue();
+ verify(mSpiedBackgroundPanelOrganizer).showBackgroundPanelLayer();
}
@Test
public void testRemoveBackgroundLayer() {
mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
- mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer();
- mTestableLooper.processAllMessages();
- assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isFalse();
+ assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isNotNull();
+
+ reset(mSpiedBackgroundPanelOrganizer);
+ mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer();
+
+ assertThat(mSpiedBackgroundPanelOrganizer.mBackgroundSurface).isNull();
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index b224ae6..911fe07 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -110,7 +110,7 @@
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true);
- when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash);
+ when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true);
when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
mDefaultEnabled);
when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
index e61f061..bea69c5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
@@ -102,7 +102,7 @@
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
- when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash);
+ when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true);
when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
mDefaultEnabled);
when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index ae1d3b2..b1434ca 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -66,7 +66,7 @@
mDisplayLayout = new DisplayLayout(mContext, mDisplay);
mSpiedTransitionState = spy(new OneHandedState());
mSpiedTutorialHandler = spy(
- new OneHandedTutorialHandler(mContext, mMockWindowManager));
+ new OneHandedTutorialHandler(mContext, mMockSettingsUtil, mMockWindowManager));
mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor);
}
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/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index a2b1f64..21329c7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -26,6 +26,7 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -275,6 +276,26 @@
}
@Test
+ public void testTransitionFilterNotRequirement() {
+ // filter that requires one opening and NO translucent apps
+ TransitionFilter filter = new TransitionFilter();
+ filter.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ filter.mRequirements[1].mFlags = FLAG_TRANSLUCENT;
+ filter.mRequirements[1].mNot = true;
+
+ final TransitionInfo openOnly = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).build();
+ assertTrue(filter.matches(openOnly));
+
+ final TransitionInfo openAndTranslucent = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ openAndTranslucent.getChanges().get(1).setFlags(FLAG_TRANSLUCENT);
+ assertFalse(filter.matches(openAndTranslucent));
+ }
+
+ @Test
public void testRegisteredRemoteTransition() {
Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
mMainExecutor, mAnimExecutor);
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index fd6bbdc..f2d7bda 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -26,6 +26,7 @@
#include "hwui/BlurDrawLooper.h"
#include <SkCanvas.h>
+#include <SkDeque.h>
#include "pipeline/skia/AnimatedDrawables.h"
#include "src/core/SkArenaAlloc.h"
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index df41011..5aad821 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -100,6 +100,9 @@
destroyContext();
ATRACE_NAME("WebViewFunctor::onDestroy");
+ if (mSurfaceControl) {
+ removeOverlays();
+ }
mCallbacks.onDestroyed(mFunctor, mData);
}
diff --git a/libs/hwui/jni/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index 6942017..b7ddd21 100644
--- a/libs/hwui/jni/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -64,7 +64,7 @@
}
static jlong validateNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) {
- size_t chunkSize = env->GetArrayLength(obj);
+ size_t chunkSize = obj != NULL ? env->GetArrayLength(obj) : 0;
if (chunkSize < (int) (sizeof(Res_png_9patch))) {
jniThrowRuntimeException(env, "Array too small for chunk.");
return NULL;
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/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 41e443f..115fb74 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1568,6 +1568,9 @@
if (isFdDuped) {
closeFileDescriptor(fileDescriptor);
}
+ if (modernFd != null) {
+ modernFd.close();
+ }
}
}
@@ -2557,17 +2560,13 @@
private void initForFilename(String filename) throws IOException {
FileInputStream in = null;
+ ParcelFileDescriptor modernFd = null;
mAssetInputStream = null;
mFilename = filename;
mIsInputStream = false;
try {
in = new FileInputStream(filename);
- ParcelFileDescriptor modernFd;
- try {
- modernFd = FileUtils.convertToModernFd(in.getFD());
- } catch (IOException e) {
- modernFd = null;
- }
+ modernFd = FileUtils.convertToModernFd(in.getFD());
if (modernFd != null) {
closeQuietly(in);
in = new FileInputStream(modernFd.getFileDescriptor());
@@ -2578,6 +2577,9 @@
loadAttributes(in);
} finally {
closeQuietly(in);
+ if (modernFd != null) {
+ modernFd.close();
+ }
}
}
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/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 2943eee..a15529e 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -36,6 +36,7 @@
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.text.TextUtils;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -52,6 +53,8 @@
* frame and meta data from an input media file.
*/
public class MediaMetadataRetriever implements AutoCloseable {
+ private static final String TAG = "MediaMetadataRetriever";
+
// borrowed from ExoPlayer
private static final String[] STANDARD_GENRES = new String[] {
// These are the official ID3v1 genres.
@@ -301,11 +304,15 @@
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IllegalArgumentException {
- ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
- if (modernFd == null) {
- _setDataSource(fd, offset, length);
- } else {
- _setDataSource(modernFd.getFileDescriptor(), offset, length);
+
+ try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+ if (modernFd == null) {
+ _setDataSource(fd, offset, length);
+ } else {
+ _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Ignoring IO error while setting data source", e);
}
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ccd830a..83bc38b2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1270,11 +1270,14 @@
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
- ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
- if (modernFd == null) {
- _setDataSource(fd, offset, length);
- } else {
- _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+ if (modernFd == null) {
+ _setDataSource(fd, offset, length);
+ } else {
+ _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Ignoring IO error while setting data source", e);
}
}
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/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 628f7ee..7f7fb60 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -292,8 +292,7 @@
}
synchronized (mRoutesLock) {
for (MediaRoute2Info route : mRoutes.values()) {
- if (sessionInfo.getSelectedRoutes().contains(route.getId())
- || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
routes.add(route);
continue;
}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 4ec79b7..3e7b886 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -895,7 +895,7 @@
throw new IOException("External storage is not mounted. Unable to install ringtones.");
}
- // Sanity-check: are we actually being asked to install an audio file?
+ // Consistency-check: are we actually being asked to install an audio file?
final String mimeType = mContext.getContentResolver().getType(fileUri);
if(mimeType == null ||
!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java
index 184b359..4e3b426 100644
--- a/media/java/android/media/metrics/PlaybackErrorEvent.java
+++ b/media/java/android/media/metrics/PlaybackErrorEvent.java
@@ -317,7 +317,7 @@
*/
public static final class Builder {
private @Nullable Exception mException;
- private int mErrorCode;
+ private int mErrorCode = ERROR_UNKNOWN;
private int mSubErrorCode;
private long mTimeSinceCreatedMillis = -1;
private Bundle mMetricsBundle = new Bundle();
diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java
index bbcc484..e71ee20 100644
--- a/media/java/android/media/metrics/PlaybackMetrics.java
+++ b/media/java/android/media/metrics/PlaybackMetrics.java
@@ -502,9 +502,9 @@
private long mMediaDurationMillis = -1;
private int mStreamSource = STREAM_SOURCE_UNKNOWN;
private int mStreamType = STREAM_TYPE_UNKNOWN;
- private int mPlaybackType = PLAYBACK_TYPE_OTHER;
+ private int mPlaybackType = PLAYBACK_TYPE_UNKNOWN;
private int mDrmType = DRM_TYPE_NONE;
- private int mContentType = CONTENT_TYPE_OTHER;
+ private int mContentType = CONTENT_TYPE_UNKNOWN;
private @Nullable String mPlayerName;
private @Nullable String mPlayerVersion;
private @NonNull List<Long> mExperimentIds = new ArrayList<>();
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 37e1415..72cddc9 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -16,14 +16,14 @@
package android.media.projection;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
-import android.media.projection.IMediaProjection;
-import android.media.projection.IMediaProjectionCallback;
import android.os.Handler;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -106,7 +106,7 @@
if (isSecure) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
- final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+ final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
height, dpi);
builder.setFlags(flags);
if (surface != null) {
@@ -141,7 +141,7 @@
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
- final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+ final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
height, dpi);
builder.setFlags(flags);
if (surface != null) {
@@ -151,6 +151,26 @@
}
/**
+ * Constructs a {@link VirtualDisplayConfig.Builder}, which will mirror the contents of a
+ * DisplayArea. The DisplayArea to mirror is from the DisplayArea the caller is launched on.
+ *
+ * @param name The name of the virtual display, must be non-empty.
+ * @param width The width of the virtual display in pixels. Must be greater than 0.
+ * @param height The height of the virtual display in pixels. Must be greater than 0.
+ * @param dpi The density of the virtual display in dpi. Must be greater than 0.
+ * @return a config representing a VirtualDisplay
+ */
+ private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
+ int width, int height, int dpi) {
+ Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
+ final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+ height, dpi);
+ builder.setWindowTokenClientToMirror(windowContext.getWindowContextToken());
+ return builder;
+ }
+
+ /**
* Creates a {@link android.hardware.display.VirtualDisplay} to capture the
* contents of the screen.
*
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 8b69d33..0037b53 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -175,7 +175,13 @@
private void onEvent(int eventType) {
synchronized (mCallbackLock) {
if (mExecutor != null && mCallback != null) {
- mExecutor.execute(() -> mCallback.onEvent(eventType));
+ mExecutor.execute(() -> {
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ mCallback.onEvent(eventType);
+ }
+ }
+ });
}
}
}
@@ -183,7 +189,13 @@
private void onDiseqcMessage(byte[] diseqcMessage) {
synchronized (mCallbackLock) {
if (mExecutor != null && mCallback != null) {
- mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+ mExecutor.execute(() -> {
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ mCallback.onDiseqcMessage(diseqcMessage);
+ }
+ }
+ });
}
}
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 3254366..088b3b6 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -629,8 +629,13 @@
synchronized (mOnResourceLostListenerLock) {
if (mOnResourceLostListener != null
&& mOnResourceLostListenerExecutor != null) {
- mOnResourceLostListenerExecutor.execute(
- () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+ mOnResourceLostListenerExecutor.execute(() -> {
+ synchronized (mOnResourceLostListenerLock) {
+ if (mOnResourceLostListener != null) {
+ mOnResourceLostListener.onResourceLost(Tuner.this);
+ }
+ }
+ });
}
}
break;
@@ -1068,7 +1073,13 @@
Log.d(TAG, "Got event from tuning. Event type: " + eventType);
synchronized (mOnTuneEventLock) {
if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) {
- mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+ mOnTuneEventExecutor.execute(() -> {
+ synchronized (mOnTuneEventLock) {
+ if (mOnTuneEventListener != null) {
+ mOnTuneEventListener.onTuneEvent(eventType);
+ }
+ }
+ });
}
}
@@ -1096,7 +1107,13 @@
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onLocked();
+ }
+ }
+ });
}
}
}
@@ -1104,7 +1121,13 @@
private void onScanStopped() {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onScanStopped();
+ }
+ }
+ });
}
}
}
@@ -1112,7 +1135,13 @@
private void onProgress(int percent) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onProgress(percent);
+ }
+ }
+ });
}
}
}
@@ -1120,7 +1149,13 @@
private void onFrequenciesReport(int[] frequency) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onFrequenciesReported(frequency);
+ }
+ }
+ });
}
}
}
@@ -1128,7 +1163,13 @@
private void onSymbolRates(int[] rate) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onSymbolRatesReported(rate);
+ }
+ }
+ });
}
}
}
@@ -1136,7 +1177,13 @@
private void onHierarchy(int hierarchy) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onHierarchyReported(hierarchy);
+ }
+ }
+ });
}
}
}
@@ -1144,7 +1191,13 @@
private void onSignalType(int signalType) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onSignalTypeReported(signalType);
+ }
+ }
+ });
}
}
}
@@ -1152,7 +1205,13 @@
private void onPlpIds(int[] plpIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onPlpIdsReported(plpIds);
+ }
+ }
+ });
}
}
}
@@ -1160,7 +1219,13 @@
private void onGroupIds(int[] groupIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onGroupIdsReported(groupIds);
+ }
+ }
+ });
}
}
}
@@ -1168,8 +1233,13 @@
private void onInputStreamIds(int[] inputStreamIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onInputStreamIdsReported(inputStreamIds);
+ }
+ }
+ });
}
}
}
@@ -1177,8 +1247,13 @@
private void onDvbsStandard(int dvbsStandandard) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onDvbsStandardReported(dvbsStandandard);
+ }
+ }
+ });
}
}
}
@@ -1186,8 +1261,13 @@
private void onDvbtStandard(int dvbtStandard) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onDvbtStandardReported(dvbtStandard);
+ }
+ }
+ });
}
}
}
@@ -1195,7 +1275,13 @@
private void onAnalogSifStandard(int sif) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onAnalogSifStandardReported(sif);
+ }
+ }
+ });
}
}
}
@@ -1203,8 +1289,13 @@
private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos);
+ }
+ }
+ });
}
}
}
@@ -1212,8 +1303,13 @@
private void onModulationReported(int modulation) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onModulationReported(modulation));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onModulationReported(modulation);
+ }
+ }
+ });
}
}
}
@@ -1221,8 +1317,13 @@
private void onPriorityReported(boolean isHighPriority) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onPriorityReported(isHighPriority));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onPriorityReported(isHighPriority);
+ }
+ }
+ });
}
}
}
@@ -1230,8 +1331,13 @@
private void onDvbcAnnexReported(int dvbcAnnex) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onDvbcAnnexReported(dvbcAnnex);
+ }
+ }
+ });
}
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 1f805d7..6c2b9e3 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -119,7 +119,13 @@
}
synchronized (mListenerLock) {
if (mExecutor != null && mListener != null) {
- mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+ mExecutor.execute(() -> {
+ synchronized (mListenerLock) {
+ if (mListener != null) {
+ mListener.onPlaybackStatusChanged(status);
+ }
+ }
+ });
}
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 2b69466..212a713 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -82,7 +82,13 @@
}
synchronized (mListenerLock) {
if (mExecutor != null && mListener != null) {
- mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+ mExecutor.execute(() -> {
+ synchronized (mListenerLock) {
+ if (mListener != null) {
+ mListener.onRecordStatusChanged(status);
+ }
+ }
+ });
}
}
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 33742ff..3db7047 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -256,7 +256,13 @@
private void onFilterStatus(int status) {
synchronized (mCallbackLock) {
if (mCallback != null && mExecutor != null) {
- mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+ mExecutor.execute(() -> {
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ mCallback.onFilterStatusChanged(this, status);
+ }
+ }
+ });
}
}
}
@@ -264,7 +270,13 @@
private void onFilterEvent(FilterEvent[] events) {
synchronized (mCallbackLock) {
if (mCallback != null && mExecutor != null) {
- mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+ mExecutor.execute(() -> {
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ mCallback.onFilterEvent(this, events);
+ }
+ }
+ });
}
}
}
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/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index e74bda8..388a65d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -1810,7 +1810,7 @@
/**
* Simple validation of JPEG image size and format.
* <p>
- * Only validate the image object sanity. It is fast, but doesn't actually
+ * Only validate the image object consistency. It is fast, but doesn't actually
* check the buffer data. Assert is used here as it make no sense to
* continue the test if the jpeg image captured has some serious failures.
* </p>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
index cbdcc36..66288f0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
@@ -572,7 +572,7 @@
/**
* Validate JPEG capture image object soundness and test.
* <p>
- * In addition to image object sanity, this function also does the decoding
+ * In addition to image object consistency, this function also does the decoding
* test, which is slower.
* </p>
*
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 54442b3..39add7e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -927,7 +927,7 @@
};
assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR));
- // Finally, do a round-trip check as a sanity
+ // Finally, do a round-trip check for consistency
checkKeyMarshal(
"android.scaler.availableInputOutputFormatsMap",
new ReprocessFormatsMap(contents),
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..51a0c99
--- /dev/null
+++ b/native/android/performance_hint.cpp
@@ -0,0 +1,240 @@
+/*
+ * 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) {
+ preferredRateNanos = -1L;
+ }
+ 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/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 3d62af0..9d3ce34 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,26 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.egg"
- android:versionCode="1"
+ android:versionCode="12"
android:versionName="1.0">
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- used for cat notifications -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+
<!-- used to save cat images -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<!-- controls -->
<uses-permission android:name="android.permission.BIND_CONTROLS" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
-
- <activity android:name=".quares.QuaresActivity"
+ <activity
+ android:name=".quares.QuaresActivity"
+ android:exported="true"
android:icon="@drawable/q_icon"
android:label="@string/q_egg_name"
- android:exported="true"
android:theme="@style/QuaresTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,9 +31,9 @@
<activity
android:name=".paint.PaintActivity"
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:exported="true"
android:icon="@drawable/p_icon"
android:label="@string/p_egg_name"
- android:exported="true"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -39,13 +41,15 @@
</activity>
<!-- Android N easter egg bits -->
- <activity android:name=".neko.NekoLand"
- android:theme="@android:style/Theme.Material.NoActionBar"
+ <activity
+ android:name=".neko.NekoLand"
android:exported="true"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Material.NoActionBar">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -54,25 +58,24 @@
<service
android:name=".neko.NekoService"
android:enabled="true"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true" >
- </service>
-
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Used to show over lock screen -->
- <activity android:name=".neko.NekoLockedActivity"
+ <activity
+ android:name=".neko.NekoLockedActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
- android:showOnLockScreen="true" />
-
+ android:showOnLockScreen="true"
+ android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" />
<!-- Used to enable easter egg -->
- <activity android:name=".neko.NekoActivationActivity"
+ <activity
+ android:name=".ComponentActivationActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.NoDisplay"
- >
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
@@ -81,37 +84,66 @@
<!-- The quick settings tile, disabled by default -->
<service
android:name=".neko.NekoTile"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:icon="@drawable/stat_icon"
android:enabled="false"
android:exported="true"
- android:label="@string/default_tile_name">
+ android:icon="@drawable/stat_icon"
+ android:label="@string/default_tile_name"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
-
- <service android:name=".neko.NekoControlsService"
- android:permission="android.permission.BIND_CONTROLS"
- android:label="@string/r_egg_name"
- android:icon="@drawable/ic_fullcat_icon"
+ <service
+ android:name=".neko.NekoControlsService"
android:enabled="false"
- android:exported="true">
+ android:exported="true"
+ android:icon="@drawable/ic_fullcat_icon"
+ android:label="@string/r_egg_name"
+ android:permission="android.permission.BIND_CONTROLS">
<intent-filter>
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
- </service>
-
- <!-- FileProvider for sending pictures -->
+ </service> <!-- FileProvider for sending pictures -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.egg.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
+ android:exported="false"
+ android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
+
+ <!-- Android S easter egg bits -->
+
+ <!-- List of all system theme colors on the device. -->
+ <activity
+ android:name=".widget.PaintChipsActivity"
+ android:theme="@android:style/Theme.Material.Wallpaper.NoTitleBar"
+ android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:label="@string/s_egg_name"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <!-- Homescreen widget also showing paint chips (may be affected by the exact position in
+ the workspace) -->
+ <receiver
+ android:name=".widget.PaintChipsWidget"
+ android:label="@string/s_egg_name"
+ android:exported="true"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.appwidget.provider"
+ android:resource="@xml/paint_chips_widget_info" />
+ </receiver>
</application>
</manifest>
diff --git a/packages/EasterEgg/build.gradle b/packages/EasterEgg/build.gradle
index 20b4698..0565369 100644
--- a/packages/EasterEgg/build.gradle
+++ b/packages/EasterEgg/build.gradle
@@ -7,8 +7,8 @@
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.0'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.android.tools.build:gradle:7.0.0-alpha08'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30"
}
}
@@ -62,6 +62,9 @@
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ buildFeatures {
+ viewBinding true
+ }
}
@@ -74,6 +77,7 @@
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
+ implementation 'com.google.android.material:material:1.3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
diff --git a/packages/EasterEgg/gradle.properties b/packages/EasterEgg/gradle.properties
index e8e6450..0b5a736 100644
--- a/packages/EasterEgg/gradle.properties
+++ b/packages/EasterEgg/gradle.properties
@@ -19,5 +19,5 @@
kotlin.code.style=official
ANDROID_X_VERSION=1+
-COMPILE_SDK=android-30
+COMPILE_SDK=android-S
BUILD_TOOLS_VERSION=28.0.3
diff --git a/packages/EasterEgg/res/drawable/android_s.xml b/packages/EasterEgg/res/drawable/android_s.xml
new file mode 100644
index 0000000..9cecab1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_s.xml
@@ -0,0 +1,23 @@
+<vector android:height="108dp" android:viewportHeight="48"
+ android:viewportWidth="48" android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <group>
+ <clip-path android:pathData="M17,14h14v20h-14z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18,21C18,21.7956 18.3161,22.5587 18.8787,23.1213C19.4413,23.6839 20.2044,24 21,24H27C27.7956,24 28.5587,24.3161 29.1213,24.8787C29.6839,25.4413 30,26.2044 30,27"
+ android:strokeColor="#ffffff" android:strokeWidth="2"/>
+ <path android:fillColor="#ffffff" android:pathData="M22,21C22.5523,21 23,20.5523 23,20C23,19.4477 22.5523,19 22,19C21.4477,19 21,19.4477 21,20C21,20.5523 21.4477,21 22,21Z"/>
+ <path android:fillColor="#ffffff" android:pathData="M26,21C26.5523,21 27,20.5523 27,20C27,19.4477 26.5523,19 26,19C25.4477,19 25,19.4477 25,20C25,20.5523 25.4477,21 26,21Z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M19.5,16.5L18,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M28.5,16.5L30,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M29.92,20C29.8637,19.6605 29.7801,19.3261 29.67,19C29.205,17.6561 28.2777,16.5211 27.0536,15.7973C25.8294,15.0735 24.388,14.8081 22.9864,15.0483C21.5847,15.2885 20.314,16.0188 19.4007,17.1088C18.4874,18.1989 17.991,19.5779 18,21"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18.08,28C18.1363,28.3395 18.2199,28.6739 18.33,29C18.795,30.3439 19.7223,31.4789 20.9464,32.2027C22.1705,32.9265 23.612,33.1919 25.0136,32.9517C26.4153,32.7115 27.686,31.9812 28.5993,30.8912C29.5126,29.8011 30.009,28.4221 30,27"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 7f8d4fa..7054962 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_s"/>
</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index 31b2a7f..d08e160 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent2_500" />
diff --git a/packages/EasterEgg/res/drawable/roundrect.xml b/packages/EasterEgg/res/drawable/roundrect.xml
new file mode 100644
index 0000000..070adad
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/roundrect.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FF000000" />
+ <corners
+ android:radius="12dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chip.xml b/packages/EasterEgg/res/layout/paint_chip.xml
new file mode 100644
index 0000000..d5745b9
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chip.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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/chip"
+ android:layout_width="10dp" android:layout_height="10dp"
+ android:layout_gravity="fill" android:layout_columnWeight="1" android:layout_rowWeight="1"
+ android:text="A1-500"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:background="@drawable/roundrect"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:layout_margin="2dp"
+ android:singleLine="true"
+ />
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chips_grid.xml b/packages/EasterEgg/res/layout/paint_chips_grid.xml
new file mode 100644
index 0000000..79f7013
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_grid.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/paint_grid"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="0dp"
+ android:orientation="vertical"
+ android:alignmentMode="alignBounds"
+ android:rowOrderPreserved="false"
+ >
+</GridLayout>
diff --git a/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
new file mode 100644
index 0000000..9893ec0
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
@@ -0,0 +1,79 @@
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="300dp"
+ android:layout_height="50dp"
+ android:alignmentMode="alignBounds"
+ android:columnCount="5"
+ android:padding="0dp"
+ android:rowCount="1"
+ android:rowOrderPreserved="false">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent3_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A3-500"
+ android:textColor="?android:attr/textColorPrimary" />
+</GridLayout>
diff --git a/packages/EasterEgg/res/values-night/themes.xml b/packages/EasterEgg/res/values-night/themes.xml
new file mode 100644
index 0000000..83ec7a5
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_900</item>
+ <item name="appWidgetTextColor">@color/light_blue_200</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/attrs.xml b/packages/EasterEgg/res/values/attrs.xml
new file mode 100644
index 0000000..97531a2
--- /dev/null
+++ b/packages/EasterEgg/res/values/attrs.xml
@@ -0,0 +1,6 @@
+<resources>
+ <declare-styleable name="AppWidgetAttrs">
+ <attr name="appWidgetBackgroundColor" format="color" />
+ <attr name="appWidgetTextColor" format="color" />
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/colors.xml b/packages/EasterEgg/res/values/colors.xml
index 1a5388b..d79e83b 100644
--- a/packages/EasterEgg/res/values/colors.xml
+++ b/packages/EasterEgg/res/values/colors.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,4 +17,8 @@
<color name="toolbar_bg_color">#FFDDDDDD</color>
<color name="paper_color">#FFFFFFFF</color>
<color name="paint_color">#FF000000</color>
+ <color name="light_blue_50">#FFE1F5FE</color>
+ <color name="light_blue_200">#FF81D4FA</color>
+ <color name="light_blue_600">#FF039BE5</color>
+ <color name="light_blue_900">#FF01579B</color>
</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/dimens.xml
index e9dcebd..0de2c3c 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values/dimens.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +15,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<dimen name="neko_display_size">64dp</dimen>
+
+ <!--
+Refer to App Widget Documentation for margin information
+http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
+ -->
+ <dimen name="widget_margin">0dp</dimen>
</resources>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 25f9421..743947a 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android R Easter Egg</string>
+ <string name="app_name" translatable="false">Android S Easter Egg</string>
<!-- name of the Q easter egg, a nonogram-style icon puzzle -->
<string name="q_egg_name" translatable="false">Icon Quiz</string>
@@ -23,4 +23,8 @@
<string name="p_egg_name" translatable="false">PAINT.APK</string>
<string name="r_egg_name" translatable="false">Cat Controls</string>
+
+ <!-- name of the S easter egg, a widget that displays the system color palette
+ in a manner similar to a set of paint samples from a hardware store -->
+ <string name="s_egg_name" translatable="false">Paint Chips</string>
</resources>
diff --git a/packages/EasterEgg/res/values/themes.xml b/packages/EasterEgg/res/values/themes.xml
new file mode 100644
index 0000000..5b16304
--- /dev/null
+++ b/packages/EasterEgg/res/values/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_600</item>
+ <item name="appWidgetTextColor">@color/light_blue_50</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/xml/paint_chips_widget_info.xml b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml
new file mode 100644
index 0000000..7780a75
--- /dev/null
+++ b/packages/EasterEgg/res/xml/paint_chips_widget_info.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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:initialLayout="@layout/paint_chip"
+ android:previewLayout="@layout/paint_chips_widget_preview"
+ android:minWidth="50dp"
+ android:minHeight="50dp"
+ android:resizeMode="horizontal|vertical"
+ android:updatePeriodMillis="86400000"
+ android:widgetCategory="home_screen"></appwidget-provider>
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
new file mode 100644
index 0000000..5820b5a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.egg.neko.NekoControlsService;
+import com.android.egg.widget.PaintChipsActivity;
+import com.android.egg.widget.PaintChipsWidget;
+
+/**
+ * Launched from the PlatLogoActivity. Enables everything else in this easter egg.
+ */
+public class ComponentActivationActivity extends Activity {
+ private static final String TAG = "EasterEgg";
+
+ private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
+
+ private void toastUp(String s) {
+ Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
+ toast.show();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final PackageManager pm = getPackageManager();
+ final ComponentName[] cns = new ComponentName[] {
+ new ComponentName(this, NekoControlsService.class),
+ new ComponentName(this, PaintChipsActivity.class),
+ new ComponentName(this, PaintChipsWidget.class)
+ };
+ final long unlockValue = Settings.System.getLong(getContentResolver(),
+ S_EGG_UNLOCK_SETTING, 0);
+ for (ComponentName cn : cns) {
+ final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
+ == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ if (unlockValue == 0) {
+ if (componentEnabled) {
+ Log.v(TAG, "Disabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDEAB");
+ } else {
+ Log.v(TAG, "Already disabled: " + cn);
+ }
+ } else {
+ if (!componentEnabled) {
+ Log.v(TAG, "Enabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDC31");
+ } else {
+ Log.v(TAG, "Already enabled: " + cn);
+ }
+ }
+ }
+
+ finish();
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
deleted file mode 100644
index df461c6..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoActivationActivity extends Activity {
- private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r";
-
- private void toastUp(String s) {
- Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- final PackageManager pm = getPackageManager();
- final ComponentName cn = new ComponentName(this, NekoControlsService.class);
- final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
- == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
- if (Settings.System.getLong(getContentResolver(),
- R_EGG_UNLOCK_SETTING, 0) == 0) {
- if (componentEnabled) {
- Log.v("Neko", "Disabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 0);
- toastUp("\uD83D\uDEAB");
- } else {
- Log.v("Neko", "Controls already disabled.");
- }
- } else {
- if (!componentEnabled) {
- Log.v("Neko", "Enabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 1);
- toastUp("\uD83D\uDC31");
- } else {
- Log.v("Neko", "Controls already enabled.");
- }
- }
- finish();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt
new file mode 100644
index 0000000..8799aec
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.egg.widget
+
+import android.app.Activity
+import android.content.res.Configuration
+import android.os.Bundle
+import android.widget.FrameLayout
+
+/**
+ * Activity to show off the current dynamic system theme in all its glory.
+ */
+class PaintChipsActivity : Activity() {
+ private lateinit var layout: FrameLayout
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ window.navigationBarColor = 0
+ window.statusBarColor = 0
+ actionBar?.hide()
+
+ layout = FrameLayout(this)
+ layout.setPadding(dp2px(8f), dp2px(8f), dp2px(8f), dp2px(8f))
+ rebuildGrid()
+
+ setContentView(layout)
+ }
+
+ fun dp2px(dp: Float): Int {
+ return (dp * resources.displayMetrics.density).toInt()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ rebuildGrid()
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+
+ rebuildGrid()
+ }
+
+ private fun rebuildGrid() {
+ layout.removeAllViews()
+ val grid = buildFullWidget(this, ClickBehavior.SHARE)
+ val asView = grid.apply(this, layout)
+ layout.addView(asView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT))
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
new file mode 100644
index 0000000..c15cabb
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
@@ -0,0 +1,293 @@
+/*
+ * 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.egg.widget
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.util.SizeF
+import android.widget.RemoteViews
+
+import com.android.egg.R
+
+/**
+ * A homescreen widget to explore the current dynamic system theme.
+ */
+class PaintChipsWidget : AppWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray
+ ) {
+ for (appWidgetId in appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ }
+ }
+
+ override fun onAppWidgetOptionsChanged(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int,
+ newOptions: Bundle?
+ ) {
+ // Log.v(TAG, "onAppWidgetOptionsChanged: id=${appWidgetId}")
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
+ }
+}
+
+const val TAG = "PaintChips"
+
+val SHADE_NUMBERS = intArrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
+
+val COLORS_NEUTRAL1 = intArrayOf(
+ android.R.color.system_neutral1_0,
+ android.R.color.system_neutral1_10,
+ android.R.color.system_neutral1_50,
+ android.R.color.system_neutral1_100,
+ android.R.color.system_neutral1_200,
+ android.R.color.system_neutral1_300,
+ android.R.color.system_neutral1_400,
+ android.R.color.system_neutral1_500,
+ android.R.color.system_neutral1_600,
+ android.R.color.system_neutral1_700,
+ android.R.color.system_neutral1_800,
+ android.R.color.system_neutral1_900,
+ android.R.color.system_neutral1_1000
+)
+
+val COLORS_NEUTRAL2 = intArrayOf(
+ android.R.color.system_neutral2_0,
+ android.R.color.system_neutral2_10,
+ android.R.color.system_neutral2_50,
+ android.R.color.system_neutral2_100,
+ android.R.color.system_neutral2_200,
+ android.R.color.system_neutral2_300,
+ android.R.color.system_neutral2_400,
+ android.R.color.system_neutral2_500,
+ android.R.color.system_neutral2_600,
+ android.R.color.system_neutral2_700,
+ android.R.color.system_neutral2_800,
+ android.R.color.system_neutral2_900,
+ android.R.color.system_neutral2_1000
+)
+
+var COLORS_ACCENT1 = intArrayOf(
+ android.R.color.system_accent1_0,
+ android.R.color.system_accent1_10,
+ android.R.color.system_accent1_50,
+ android.R.color.system_accent1_100,
+ android.R.color.system_accent1_200,
+ android.R.color.system_accent1_300,
+ android.R.color.system_accent1_400,
+ android.R.color.system_accent1_500,
+ android.R.color.system_accent1_600,
+ android.R.color.system_accent1_700,
+ android.R.color.system_accent1_800,
+ android.R.color.system_accent1_900,
+ android.R.color.system_accent1_1000
+)
+
+var COLORS_ACCENT2 = intArrayOf(
+ android.R.color.system_accent2_0,
+ android.R.color.system_accent2_10,
+ android.R.color.system_accent2_50,
+ android.R.color.system_accent2_100,
+ android.R.color.system_accent2_200,
+ android.R.color.system_accent2_300,
+ android.R.color.system_accent2_400,
+ android.R.color.system_accent2_500,
+ android.R.color.system_accent2_600,
+ android.R.color.system_accent2_700,
+ android.R.color.system_accent2_800,
+ android.R.color.system_accent2_900,
+ android.R.color.system_accent2_1000
+)
+
+var COLORS_ACCENT3 = intArrayOf(
+ android.R.color.system_accent3_0,
+ android.R.color.system_accent3_10,
+ android.R.color.system_accent3_50,
+ android.R.color.system_accent3_100,
+ android.R.color.system_accent3_200,
+ android.R.color.system_accent3_300,
+ android.R.color.system_accent3_400,
+ android.R.color.system_accent3_500,
+ android.R.color.system_accent3_600,
+ android.R.color.system_accent3_700,
+ android.R.color.system_accent3_800,
+ android.R.color.system_accent3_900,
+ android.R.color.system_accent3_1000
+)
+
+var COLOR_NAMES = arrayOf(
+ "N1", "N2", "A1", "A2", "A3"
+)
+
+var COLORS = arrayOf(
+ COLORS_NEUTRAL1,
+ COLORS_NEUTRAL2,
+ COLORS_ACCENT1,
+ COLORS_ACCENT2,
+ COLORS_ACCENT3
+)
+
+internal fun updateAppWidget(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int
+) {
+ // val opts = appWidgetManager.getAppWidgetOptions(appWidgetId)
+ // Log.v(TAG, "requested sizes=${opts[OPTION_APPWIDGET_SIZES]}")
+
+ val allSizes = mapOf(
+ SizeF(50f, 50f)
+ to buildWidget(context, 1, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 50f)
+ to buildWidget(context, 1, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 50f)
+ to buildWidget(context, 1, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 50f)
+ to buildWidget(context, 1, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 50f)
+ to buildWidget(context, 1, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 120f)
+ to buildWidget(context, 3, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 120f)
+ to buildWidget(context, 3, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 120f)
+ to buildWidget(context, 3, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 120f)
+ to buildWidget(context, 3, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 120f)
+ to buildWidget(context, 3, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 250f)
+ to buildWidget(context, 5, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 250f)
+ to buildWidget(context, 5, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 250f)
+ to buildWidget(context, 5, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 250f)
+ to buildWidget(context, 5, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 250f)
+ to buildWidget(context, 5, 5, ClickBehavior.LAUNCH),
+
+ SizeF(300f, 300f)
+ to buildWidget(context, SHADE_NUMBERS.size, COLORS.size, ClickBehavior.LAUNCH)
+ )
+
+ // Instruct the widget manager to update the widget
+ appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(allSizes))
+}
+
+fun buildFullWidget(context: Context, clickable: ClickBehavior): RemoteViews {
+ return buildWidget(context, SHADE_NUMBERS.size, COLORS.size, clickable)
+}
+
+fun buildWidget(context: Context, numShades: Int, numColors: Int, clickable: ClickBehavior):
+ RemoteViews {
+ val grid = RemoteViews(context.packageName, R.layout.paint_chips_grid)
+
+ // shouldn't be necessary but sometimes the RV instructions get played twice in launcher.
+ grid.removeAllViews(R.id.paint_grid)
+
+ grid.setInt(R.id.paint_grid, "setRowCount", numShades)
+ grid.setInt(R.id.paint_grid, "setColumnCount", numColors)
+
+ Log.v(TAG, "building widget: shade rows=$numShades, color columns=$numColors")
+
+ COLORS.forEachIndexed colorLoop@{ i, colorlist ->
+ when (colorlist) {
+ COLORS_NEUTRAL1 -> if (numColors < 2) return@colorLoop
+ COLORS_NEUTRAL2 -> if (numColors < 4) return@colorLoop
+ COLORS_ACCENT2 -> if (numColors < 3) return@colorLoop
+ COLORS_ACCENT3 -> if (numColors < 5) return@colorLoop
+ else -> {} // always do ACCENT1
+ }
+ colorlist.forEachIndexed shadeLoop@{ j, resId ->
+ when (SHADE_NUMBERS[j]) {
+ 500 -> {}
+ 300, 700 -> if (numShades < 3) return@shadeLoop
+ 100, 900 -> if (numShades < 5) return@shadeLoop
+ else -> if (numShades < SHADE_NUMBERS.size) return@shadeLoop
+ }
+ val cell = RemoteViews(context.packageName, R.layout.paint_chip)
+ cell.setTextViewText(R.id.chip, "${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]}")
+ val textColor = if (SHADE_NUMBERS[j] > 500)
+ colorlist[0]
+ else colorlist[colorlist.size - 1]
+ cell.setTextColor(R.id.chip, context.getColor(textColor))
+ cell.setColorStateList(R.id.chip, "setBackgroundTintList", resId)
+ val text = """
+ ${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]} (@${
+ context.resources.getResourceName(resId) })
+ currently: #${ String.format("%06x", context.getColor(resId) and 0xFFFFFF) }
+ """.trimIndent()
+ when (clickable) {
+ ClickBehavior.SHARE -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeTextSharePendingIntent(context, text)
+ )
+ ClickBehavior.LAUNCH -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeActivityLaunchPendingIntent(context)
+ )
+ ClickBehavior.NONE -> { }
+ }
+ grid.addView(R.id.paint_grid, cell)
+ }
+ }
+
+ return grid
+}
+
+enum class ClickBehavior {
+ NONE,
+ SHARE,
+ LAUNCH
+}
+
+fun makeTextSharePendingIntent(context: Context, text: String): PendingIntent {
+ val shareIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_TEXT, text)
+ type = "text/plain"
+ }
+
+ val chooserIntent = Intent.createChooser(shareIntent, null).apply {
+ identifier = text // incredible quality-of-life improvement, thanks framework team
+ }
+
+ return PendingIntent.getActivity(context, 0, chooserIntent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
+
+fun makeActivityLaunchPendingIntent(context: Context): PendingIntent {
+ return PendingIntent.getActivity(context, 0,
+ Intent().apply {
+ component = ComponentName(context, PaintChipsActivity::class.java)
+ action = Intent.ACTION_MAIN
+ },
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
index bc740ab..6a9145d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
@@ -66,8 +66,8 @@
/**
* In order to make sure that the Wearable Asset Manager has a reasonable apk that can be used
* by the PackageManager, we will parse it before sending it to the PackageManager.
- * Unfortunately, PackageParser needs a file to parse. So, we have to temporarily convert the fd
- * to a File.
+ * Unfortunately, ParsingPackageUtils needs a file to parse. So, we have to temporarily convert
+ * the fd to a File.
*
* @param context
* @param fd FileDescriptor to convert to 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/Android.bp b/packages/SettingsLib/Android.bp
index 2b8f049..e8ed88f 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -37,6 +37,7 @@
"SettingsLibProgressBar",
"SettingsLibAdaptiveIcon",
"SettingsLibRadioButtonPreference",
+ "SettingsLibSelectorWithWidgetPreference",
"SettingsLibDisplayDensityUtils",
"SettingsLibUtils",
"SettingsLibEmergencyNumber",
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..1f80a3e 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -170,7 +170,14 @@
}
/**
- * Sets image drawable to display image in {@link LottieAnimationView}
+ * Gets the lottie illustration resource id.
+ */
+ public int getLottieAnimationResId() {
+ return mImageResId;
+ }
+
+ /**
+ * Sets the image drawable to display image in {@link LottieAnimationView}.
*
* @param imageDrawable the drawable of an image
*/
@@ -183,7 +190,16 @@
}
/**
- * Sets image uri to display image in {@link LottieAnimationView}
+ * Gets the image drawable from display image in {@link LottieAnimationView}.
+ *
+ * @return the drawable of an image
+ */
+ public Drawable getImageDrawable() {
+ return mImageDrawable;
+ }
+
+ /**
+ * Sets the image uri to display image in {@link LottieAnimationView}.
*
* @param imageUri the Uri of an image
*/
@@ -195,6 +211,15 @@
}
}
+ /**
+ * Gets the image uri from display image in {@link LottieAnimationView}.
+ *
+ * @return the Uri of an image
+ */
+ public Uri getImageUri() {
+ return mImageUri;
+ }
+
private void resetImageResourceCache() {
mImageDrawable = null;
mImageUri = null;
@@ -267,26 +292,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/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
index 28ff71f..1387daa 100644
--- a/packages/SettingsLib/RadioButtonPreference/Android.bp
+++ b/packages/SettingsLib/RadioButtonPreference/Android.bp
@@ -15,6 +15,7 @@
static_libs: [
"androidx.preference_preference",
+ "SettingsLibSelectorWithWidgetPreference",
"SettingsLibSettingsTheme",
],
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
index f50127f..02d3c06 100644
--- a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -26,6 +26,10 @@
import androidx.preference.PreferenceViewHolder;
/**
+ * DEPRECATED. Please use SelectorWithWidgetPreference instead.
+ *
+ * This file has been moved there and will be removed once all callers are updated.
+ *
* Check box preference with check box replaced by radio button.
*
* Functionally speaking, it's actually a CheckBoxPreference. We only modified
@@ -37,6 +41,8 @@
*
* RadioButtonPreference can assign a extraWidgetListener to show a gear icon
* on the right side that can open another page.
+ *
+ * @Deprecated
*/
public class RadioButtonPreference extends CheckBoxPreference {
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/SelectorWithWidgetPreference/Android.bp b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
new file mode 100644
index 0000000..bcc64d3
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
@@ -0,0 +1,27 @@
+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_library {
+ name: "SettingsLibSelectorWithWidgetPreference",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.preference_preference",
+ "SettingsLibSettingsTheme",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+}
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml b/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml
new file mode 100644
index 0000000..51fc7ed
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml
new file mode 100644
index 0000000..6521bc9
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
new file mode 100644
index 0000000..8bb56ff
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
@@ -0,0 +1,123 @@
+<?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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="20dp"
+ android:gravity="center"
+ android:minWidth="56dp"
+ android:orientation="vertical"/>
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:minWidth="32dp"
+ android:orientation="horizontal"
+ android:layout_marginEnd="16dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ settings:maxWidth="@dimen/secondary_app_icon_size"
+ settings:maxHeight="@dimen/secondary_app_icon_size"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+ <LinearLayout
+ android:id="@+id/summary_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewStart"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ <TextView
+ android:id="@+id/appendix"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewEnd"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="1"
+ android:visibility="gone"
+ android:ellipsize="end"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/selector_extra_widget_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+ <View
+ android:layout_width=".75dp"
+ android:layout_height="32dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp"
+ android:background="?android:attr/dividerVertical" />
+ <ImageView
+ android:id="@+id/selector_extra_widget"
+ android:layout_width="match_parent"
+ android:minWidth="@dimen/two_target_min_width"
+ android:layout_height="fill_parent"
+ android:src="@drawable/ic_settings_accent"
+ android:contentDescription="@string/settings_label"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml
new file mode 100644
index 0000000..6dd1670
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@null"
+ android:focusable="false"
+ android:clickable="false" />
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
new file mode 100644
index 0000000..cf6371d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@null"
+ android:focusable="false"
+ android:clickable="false" />
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml
new file mode 100644
index 0000000..ff3f90c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Content description for RadioButton with extra gear icon [CHAR LIMIT=NONE] -->
+ <string name="settings_label">Settings</string>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
new file mode 100644
index 0000000..1ecc422
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -0,0 +1,203 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * Selector preference (checkbox or radio button) with an optional additional widget.
+ *
+ * Functionally speaking, it's a CheckBoxPreference. When styled like a radio button,
+ * it only "looks like" a RadioButtonPreference.
+ *
+ * In other words, there's no "RadioButtonPreferenceGroup" in this
+ * implementation. When you check one preference, if you want to
+ * uncheck all the other preferences, you should do that by code yourself.
+ *
+ * SelectorWithWidgetPreference can assign a extraWidgetListener to show a gear icon
+ * on the right side that can open another page.
+ */
+public class SelectorWithWidgetPreference extends CheckBoxPreference {
+
+ /**
+ * Interface definition for a callback to be invoked when the preference is clicked.
+ */
+ public interface OnClickListener {
+ /**
+ * Called when a preference has been clicked.
+ *
+ * @param emiter The clicked preference
+ */
+ void onRadioButtonClicked(SelectorWithWidgetPreference emiter);
+ }
+
+ private OnClickListener mListener = null;
+ private View mAppendix;
+ private int mAppendixVisibility = -1;
+
+ private View mExtraWidgetContainer;
+ private ImageView mExtraWidget;
+ private boolean mIsCheckBox = false; // whether to display this button as a checkbox
+
+ private View.OnClickListener mExtraWidgetOnClickListener;
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ * @param defStyle An attribute in the current theme that contains a reference to a style
+ * resource that supplies default values for the view. Can be 0 to not
+ * look for defaults.
+ */
+ public SelectorWithWidgetPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ */
+ public SelectorWithWidgetPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * Constructor to create a preference, which will display with a checkbox style.
+ *
+ * @param context The {@link Context} this is associated with.
+ * @param isCheckbox Whether this preference should display as a checkbox.
+ */
+ public SelectorWithWidgetPreference(Context context, boolean isCheckbox) {
+ super(context, null);
+ mIsCheckBox = isCheckbox;
+ init();
+ }
+
+ /**
+ * Constructor to create a preference.
+ *
+ * @param context The Context this is associated with.
+ */
+ public SelectorWithWidgetPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the callback to be invoked when this preference is clicked by the user.
+ *
+ * @param listener The callback to be invoked
+ */
+ public void setOnClickListener(OnClickListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Processes a click on the preference.
+ */
+ @Override
+ public void onClick() {
+ if (mListener != null) {
+ mListener.onRadioButtonClicked(this);
+ }
+ }
+
+ /**
+ * Binds the created View to the data for this preference.
+ *
+ * <p>This is a good place to grab references to custom Views in the layout and set
+ * properties on them.
+ *
+ * <p>Make sure to call through to the superclass's implementation.
+ *
+ * @param holder The ViewHolder that provides references to the views to fill in. These views
+ * will be recycled, so you should not hold a reference to them after this method
+ * returns.
+ */
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View summaryContainer = holder.findViewById(R.id.summary_container);
+ if (summaryContainer != null) {
+ summaryContainer.setVisibility(
+ TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+ mAppendix = holder.findViewById(R.id.appendix);
+ if (mAppendix != null && mAppendixVisibility != -1) {
+ mAppendix.setVisibility(mAppendixVisibility);
+ }
+ }
+
+ mExtraWidget = (ImageView) holder.findViewById(R.id.selector_extra_widget);
+ mExtraWidgetContainer = holder.findViewById(R.id.selector_extra_widget_container);
+
+ setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
+ }
+
+ /**
+ * Set the visibility state of appendix view.
+ *
+ * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
+ */
+ public void setAppendixVisibility(int visibility) {
+ if (mAppendix != null) {
+ mAppendix.setVisibility(visibility);
+ }
+ mAppendixVisibility = visibility;
+ }
+
+ /**
+ * Sets the callback to be invoked when extra widget is clicked by the user.
+ *
+ * @param listener The callback to be invoked
+ */
+ public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
+ mExtraWidgetOnClickListener = listener;
+
+ if (mExtraWidget == null || mExtraWidgetContainer == null) {
+ return;
+ }
+
+ mExtraWidget.setOnClickListener(mExtraWidgetOnClickListener);
+
+ mExtraWidgetContainer.setVisibility((mExtraWidgetOnClickListener != null)
+ ? View.VISIBLE : View.GONE);
+ }
+
+ private void init() {
+ if (mIsCheckBox) {
+ setWidgetLayoutResource(R.layout.preference_widget_checkbox);
+ } else {
+ setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+ }
+ setLayoutResource(R.layout.preference_selector_with_widget);
+ setIconSpaceReserved(false);
+ }
+}
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/lint-baseline.xml b/packages/SettingsLib/lint-baseline.xml
index f6d6ca6..d6ea73d 100644
--- a/packages/SettingsLib/lint-baseline.xml
+++ b/packages/SettingsLib/lint-baseline.xml
@@ -892,4 +892,26 @@
column="59"/>
</issue>
+ <issue
+ id="NewApi"
+ message="Call requires API level S (current min is 29): `android.os.UserManager#isUserForeground`"
+ errorLine1=" .getSystemService(UserManager.class).isUserForeground();"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java"
+ line="120"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 29): `android.os.UserManager#isUserForeground`"
+ errorLine1=" .getSystemService(UserManager.class).isUserForeground();"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java"
+ line="120"
+ column="54"/>
+ </issue>
+
</issues>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0442ba2..99edaff 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktiveer Wi-Fi-woordryke aanmelding"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Regulering van Wi-Fi-opsporing"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nie-aanhoudende MAC-verewekansiging vir wi-fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nie-aanhoudende MAC-verewekansiging vir wi-fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data is altyd aktief"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardewareversnelling vir verbinding"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Wys opsies vir draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag batteryverbruik en verbeter netwerk se werkverrigting"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wanneer hierdie modus geaktiveer is, kan hierdie toestel se MAC-adres verander elke keer wanneer dit aan \'n netwerk koppel waarvoor MAC-verewekansiging geaktiveer is."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wanneer hierdie modus geaktiveer is, kan hierdie toestel se MAC-adres verander elke keer wanneer dit aan \'n netwerk koppel waarvoor MAC-verewekansiging geaktiveer is."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Beperk"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Onbeperk"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Loggerbuffer se groottes"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 6d314ce..a6aa725 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"የWi‑Fi ተጨማሪ ቃላት ምዝግብ ማስታወሻ መያዝ"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"የWi-Fi ወጥ ያልሆነ ማክ የዘፈቀደ ማድረግ"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"የWi-Fi ወጥ ያልሆነ ማክ የዘፈቀደ ማድረግ"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"የተንቀሳቃሽ ስልክ ውሂብ ሁልጊዜ ገቢር ነው"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"የባትሪ መላሸቅን ይቀንሳል እንዲሁም የአውታረ መረብ አፈጻጸም ብቃትን ያሻሽላል"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ይህ ሁነታ ስራ ሲጀምር ይህ መሣሪያ የዘፈቀደ የማክ አድራሻ ስራ ከነቃለት አውታረ መረብ ጋር በተገናኘ እያንዳንዱ ጊዜ የመሣሪያው የማክ አድራሻ ሊቀየር ይችላል።"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ይህ ሁነታ ሲነቃ የዚህ መሣሪያ የማክ አድራሻ የዘፈቀደ የማክ አድራሻ ከነቃለት አውታረ መረብ ጋር በተገናኘ ጊዜ ሁሉ ሊቀየር ይችላል።"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"የሚለካ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ያልተለካ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"የምዝግብ ማስታወሻ ያዥ መጠኖች"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 881b76b..24d9873 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"تفعيل تسجيل Wi‑Fi Verbose"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"تقييد البحث عن شبكات Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"التوزيع العشوائي لعناوين MAC غير الثابتة لشبكة Wi‑Fi."</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"التوزيع العشوائي لعناوين MAC غير الثابتة لشبكة Wi‑Fi."</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"بيانات الجوّال نشطة دائمًا"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"تسريع الأجهزة للتوصيل"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"لتقليل استهلاك البطارية وتحسين أداء الشبكة"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"عند تفعيل هذا الوضع، قد يتم تغيير عنوان MAC لهذا الجهاز في كل مرة تتصل فيها بشبكة تم تفعيل التوزيع العشوائي لعناوين MAC عليها."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"عند تفعيل هذا الوضع، قد يتم تغيير عنوان MAC لهذا الجهاز في كل مرة تتصل فيها بشبكة تم تفعيل التوزيع العشوائي لعناوين MAC عليها."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"تفرض تكلفة استخدام"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"بدون قياس"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 1ae3452..6dd95a3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ৱাই-ফাই স্কেনৰ নিয়ন্ত্ৰণ"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"অবিৰত ৱাই-ফাই সংযোগ নথকা MACৰ যাদৃচ্ছিকীকৰণ"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"অবিৰত ৱাই-ফাই সংযোগ নথকা MACৰ যাদৃচ্ছিকীকৰণ"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ম’বাইল ডেটা সদা-সক্ৰিয়"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"বেটাৰীৰ খৰচ কমায় আৰু নেটৱৰ্কৰ কাৰ্যক্ষমতা বৃদ্ধি কৰে"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"এই ম\'ডটো সক্ষম কৰিলে, এই ডিভাইচটোৱে MAC যাদৃচ্ছিকীকৰণ সক্ষম কৰি থোৱা কোনো নেটৱর্কত প্ৰতিবাৰ সংযোগ হোৱাৰ সময়ত ইয়াৰ MAC ঠিকনাটো সলনি হ\'ব পাৰে।"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"এই ম’ডটো সক্ষম হৈ থাকিলে, এই ডিভাইচটোৱে MAC যাদৃচ্ছিকীকৰণ সক্ষম কৰি থোৱা কোনো নেটৱৰ্কত প্ৰতিবাৰ সংযোগ হোৱাৰ সময়ত ইয়াৰ MAC ঠিকনাটো হয়তো সলনি হ’ব।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"নিৰিখ-নিৰ্দিষ্ট"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"নিৰিখ অনিৰ্দিষ্ট"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"লগাৰৰ বাফাৰৰ আকাৰ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index c991912..0c91459 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz monitor sertifikatlaşması"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Çoxsözlü Girişə icazə verin"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi axtarışının məhdudlaşdırılması"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi müvəqqəti MAC randomizasiyası"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi müvəqqəti MAC randomizasiyası"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil data həmişə aktiv"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Modem rejimində cihaz sürətləndiricisi"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazları adsız göstərilsin"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorların sertifikasiya parametrləri göstərilsin"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Enerji sərfiyyatını azaldır və şəbəkənin işini yaxşılaşdırır"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejimdə şəbəkəyə hər dəfə qoşulanda cihaza təsadüfi MAC ünvanı verilə bilər."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu rejim aktiv edildikdə, bu cihaz hər dəfə MAC randomizasiyası aktiv olan şəbəkəyə qoşulanda onun MAC ünvanı dəyişə bilər."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Tarif sayğacılı"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Limitsiz"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi ölçüsü"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 32a08ad..4db3717 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikacija bežičnog ekrana"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljniju evidenciju za Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje WiFi skeniranja"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nasumično razvrstavanje MAC adresa po WiFi-ju sa prekidima"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumično razvrstavanje MAC adresa po WiFi-ju sa prekidima"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci su uvek aktivni"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje privezivanja"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikazuje opcije za sertifikaciju bežičnog ekrana"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava učinak mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je ovaj režim omogućen, MAC adresa ovog uređaja može da se promeni svaki put kada se poveže sa mrežom na kojoj je omogućeno nasumično razvrstavanje MAC adresa."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je ovaj režim omogućen, MAC adresa ovog uređaja može da se promeni svaki put kada se poveže sa mrežom na kojoj je omogućeno nasumično razvrstavanje MAC adresa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sa ograničenjem"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine bafera podataka u programu za evidentiranje"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 710ca32..604610b 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -172,7 +172,7 @@
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Гэты модуль сінтэзу гаворкі можа збіраць увесь тэкст, які будзе прамоўлены, у тым ліку асабістыя дадзеныя, напрыклад паролі і нумары крэдытных карт. Ён адносіцца да модуля <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Уключыць гэты модуль сінтэзу гаворкі?"</string>
<string name="tts_engine_network_required" msgid="8722087649733906851">"Гэта мова патрабуе актыўнага падключэння да сеткі, каб выконваць функцыю прамаўлення тэксту."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Гэта прыклад сінтэзу гаворкі"</string>
- <string name="tts_status_title" msgid="8190784181389278640">"Статус мовы па змаўчанні"</string>
+ <string name="tts_status_title" msgid="8190784181389278640">"Статус стандартнай мовы"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> цалкам падтрымліваецца"</string>
<string name="tts_status_requires_network" msgid="8327617638884678896">"Для <xliff:g id="LOCALE">%1$s</xliff:g> патрабуецца падлучэнне да сеткі"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> не падтрымліваецца"</string>
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Сертыфікацыя бесправаднога экрана"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Уключыць падрабязны журнал Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Рэгуляванне пошуку сетак Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Рандамізацыя выпадковых MAC-адрасоў у сетках Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Рандамізацыя выпадковых MAC-адрасоў у сетках Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мабільная перадача даных заўсёды актыўная"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратнае паскарэнне ў рэжыме мадэма"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Паказаць опцыі сертыфікацыі бесправаднога экрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зніжае расход зараду акумулятара і павышае прадукцыйнасць мабільных сетак"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Калі ўключаны гэты рэжым, MAC-адрас гэтай прылады можа змяняцца падчас кожнага падключэння да сеткі з актыўнай рандамізацыяй MAC-адрасоў."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Калі ўключаны гэты рэжым, MAC-адрас гэтай прылады можа змяняцца падчас кожнага падключэння да сеткі з актыўнай рандамізацыяй MAC-адрасоў."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Сетка з улікам трафіка"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Сетка без уліку трафіка"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Памеры буфера журнала"</string>
@@ -388,7 +388,7 @@
<string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"Збой пры ўсталёўцы паролю для рэзервовага капіявання"</string>
<string name="loading_injected_setting_summary" msgid="8394446285689070348">"Ідзе загрузка…"</string>
<string-array name="color_mode_names">
- <item msgid="3836559907767149216">"Сочны (па змаўчанні)"</item>
+ <item msgid="3836559907767149216">"Насычаны (стандартна)"</item>
<item msgid="9112200311983078311">"Натуральныя"</item>
<item msgid="6564241960833766170">"Стандартны"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 78aea78..39a1ff2 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Безжичен дисплей"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Активиране на „многословно“ регистр. на Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничаване на сканирането за Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Рандомизиране на временните MAC адреси за Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Рандомизиране на временните MAC адреси за Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Винаги активни мобилни данни"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардуерно ускорение на тетъринга"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показване на опциите за сертифициране на безжичния дисплей"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Намалява изразходването на батерията и подобрява ефективността на мрежата"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Когато този режим е включен, MAC адресът на устройството може да се променя при всяко свързване с мрежа, за която е активирана функцията за рандомизиране на MAC адреса."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Когато този режим е включен, MAC адресът на устройството може да се променя при всяко свързване с мрежа, за която е активирана функцията за рандомизиране на MAC адреса."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"С отчитане"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без отчитане"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Размери на регистрац. буфери"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 6e26ed4..0fd9ae5 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -252,7 +252,8 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ওয়্যারলেস ডিসপ্লে সার্টিফিকেশন"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"ওয়াই-ফাই ভারবোস লগিং চালু করুন"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ওয়াই-ফাই স্ক্যান থ্রোটলিং"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"অল্প সময় ওয়াই-ফাই নেটওয়ার্কে যুক্ত হয় এমন MAC অ্যাড্রেস র্যান্ডমাইজেশনের সুবিধা"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
+ <skip />
<string name="mobile_data_always_on" msgid="8275958101875563572">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
@@ -284,7 +285,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ব্যাটারির খরচ কমায় এবং নেটওয়ার্কের পারফর্ম্যান্স উন্নত করে"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"এই মোডটি চালু থাকার সময়, MAC র্যান্ডমাইজেশন চালু হওয়া এমন কোনও নেটওয়ার্কে কানেক্ট করার সময় এই ডিভাইসের MAC অ্যাড্রেস পরিবর্তিত হতে পারে।"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"মিটার্ড"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"পরিমাপ করা নয়"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"লগার বাফারের আকারগুলি"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 26b2db4..5b51efa 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljni zapisnik za WiFi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje skeniranja WiFi-ja"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nasumičan odabir MAC adrese prema WiFi mreži s prekidima"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumičan odabir MAC adrese prema WiFi mreži s prekidima"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Prijenos podataka na mobilnoj mreži uvijek aktivan"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzavanje za povezivanje putem mobitela"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećani nivo zapisnika za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava performanse mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je omogućen ovaj način rada, MAC adresa ovog uređaja se može promijeniti svaki put kada se poveže na mrežu koja ima omogućen nasumični odabir MAC adresa."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je omogućen ovaj način rada, MAC adresa ovog uređaja se može promijeniti svaki put kada se poveže na mrežu koja ima omogućen nasumični odabir MAC adresa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"S naplatom"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mreža bez naplate"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međumemorije zapisnika"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 261face..948d3a0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Activa el registre Wi‑Fi detallat"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitació de la cerca de xarxes Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Aleatorització de MAC no persistent per a connexions Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorització de MAC no persistent per a connexions Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dades mòbils sempre actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Acceleració per maquinari per a compartició de xarxa"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra les opcions per a la certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Augmenta el nivell de registre de la connexió Wi‑Fi i es mostra per SSID RSSI al selector de Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Redueix el consum de bateria i millora el rendiment de la xarxa"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quan aquest mode està activat, és possible que l’adreça MAC d’aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quan aquest mode està activat, és possible que l’adreça MAC d\'aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la mem. intermèdia del registrador"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index f589533..0e15848 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné protokolování Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Přibrždění vyhledávání Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Při připojování k sítím Wi‑Fi používat proměnlivé náhodné adresy MAC"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Při připojování k sítím Wi‑Fi používat proměnlivé náhodné adresy MAC"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilní data jsou vždy aktivní"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarová akcelerace tetheringu"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Snižuje vyčerpávání baterie a vylepšuje výkon sítě"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Když je tento režim aktivován, adresa MAC tohoto zařízení se může změnit pokaždé, když se zařízení připojí k síti s aktivovanou randomizací adres MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Když je tento režim aktivován, adresa MAC tohoto zařízení se může změnit pokaždé, když se zařízení připojí k síti s aktivovanou randomizací adres MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Měřená"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neměřená"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávací paměť protokolovacího nástroje"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 67bc849..4fdf435 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivér detaljeret Wi-Fi-logføring"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrænsning af Wi-Fi-scanning"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Ikke-vedvarende MAC-randomisering via Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ikke-vedvarende MAC-randomisering via Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er altid aktiveret"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareacceleration ved netdeling"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis valgmuligheder for certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reducerer batteriforbruget og forbedrer netværkets effektivitet"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Når denne tilstand er aktiveret, skifter enhedens MAC-adresse muligvis, hver gang den opretter forbindelse til et netværk, hvor MAC-randomisering er aktiveret."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Når denne tilstand er aktiveret, skifter enhedens MAC-adresse muligvis, hver gang den opretter forbindelse til et netværk, hvor MAC-randomisering er aktiveret."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Forbrugsafregnet"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ikke forbrugsafregnet"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Størrelser for Logger-buffer"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 5e026e5..489c7c7 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Zertifizierung für kabellose Übertragung"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Ausführliche WLAN-Protokollierung aktivieren"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Drosselung der WLAN-Suche"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Unbeständige MAC-Randomisierung für WLAN"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nicht persistente, zufällige Generierung von MAC-Adressen für WLAN"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile Datennutzung immer aktiviert"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarebeschleunigung für Tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"WLAN-Protokollierungsebene erhöhen, in WLAN-Auswahl für jede SSID RSSI anzeigen"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen randomisiert werden."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen zufällig generiert werden."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ohne Datenlimit"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 9bf28cb..8cd8387 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Ενεργοποίηση λεπτομερ. καταγραφής Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Περιορισμός σάρωσης Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Μη σταθερή τυχαία σειρά MAC σε Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Μη σταθερή τυχαία σειρά MAC σε Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Σύνδεση επιτάχυνσης υλικού"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Περιορίζει την κατανάλωση της μπαταρίας και βελτιώνει την απόδοση του δικτύου"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Όταν ενεργοποιηθεί αυτή η λειτουργία, η διεύθυνση MAC αυτής της συσκευής μπορεί να αλλάζει κάθε φορά που συνδέεται σε ένα δίκτυο όπου έχει ενεργοποιηθεί η τυχαιοποίηση διευθύνσεων MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Όταν ενεργοποιηθεί αυτή η λειτουργία, η διεύθυνση MAC αυτής της συσκευής μπορεί να αλλάζει κάθε φορά που συνδέεται σε ένα δίκτυο όπου έχει ενεργοποιηθεί η τυχαία σειρά διευθύνσεων MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Μέτρηση με βάση τη χρήση"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Χωρίς μέτρηση με βάση τη χρήση"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Μέγεθος προσωρινής μνήμης για τη λειτουργία καταγραφής"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index c1d4ab8..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi non‑persistent MAC randomisation"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index c9fc70d..4ad9894 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi non‑persistent MAC randomisation"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index c1d4ab8..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi non‑persistent MAC randomisation"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index c1d4ab8..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi non‑persistent MAC randomisation"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 0212719..c8a7363 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi Verbose Logging"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi non‑persistent MAC randomization"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomization"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain & improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time it connects to a network that has MAC randomization enabled."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time it connects to a network that has MAC randomization enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7755cb7..27fbf44 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro detallado de Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación de búsqueda de Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Aleatorización de MAC no persistente para conexiones Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorización de MAC no persistente para conexiones Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activados"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware de conexión mediante dispositivo móvil"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"De uso medido"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index d9db99e..f33a29d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro de Wi-Fi detallado"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar búsqueda de redes Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Aleatorización de MAC no persistente para conexiones Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorización de MAC no persistente en conexiones Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activos"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración por hardware para conexión compartida"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Muestra opciones para la certificación de la pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta el nivel de registro de la conexión Wi-Fi y se muestra por SSID RSSI en el selector Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de las redes"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Medida"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"No medida"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños del búfer para registrar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index d835cb9..0ede248 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Juhtmeta ekraaniühenduse sertifitseerimine"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Luba WiFi sõnaline logimine"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"WiFi-skannimise ahendamine"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"WiFi-võrgu mittepüsiva MAC-aadressi juhuslikustamine"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"WiFi-võrgu mittepüsiva MAC-aadressi juhuslikustamine"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Hoia mobiilne andmeside alati aktiivne"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Ühenduse jagamise riistvaraline kiirendus"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Aeglustab aku tühjenemist ja parandab võrgu toimivust"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kui see režiim on lubatud, võidakse selle seadme MAC-aadressi muuta iga kord, kui see ühendatakse võrguga, milles on juhuslikustatud MAC-aadressi määramine lubatud."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kui see režiim on lubatud, võidakse selle seadme MAC-aadressi muuta iga kord, kui see ühendatakse võrguga, milles on juhuslikustatud MAC-aadressi määramine lubatud."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mahupõhine"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mittemahupõhine"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logija puhvri suurused"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index a7f5eac5..1f8d616 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Hari gabe bistaratzeko ziurtagiria"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Gaitu wifi-sareetan saioa hasteko modu xehatua"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-sareen bilaketaren muga"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wifi-konexioetan iraunkorrak ez diren MAC helbideak ausaz antolatzea"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wifi-konexioetan iraunkorrak ez diren MAC helbideak ausaz antolatzea"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Datu-konexioa beti aktibo"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Modu hau gaituta dagoenean, baliteke gailuaren MAC helbidea aldatzea MAC helbideak ausaz antolatzeko aukera gaituta daukan sare batera konektatzen den bakoitzean."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Modu hau gaituta dagoenean, baliteke gailuaren MAC helbidea aldatzea MAC helbideak ausaz antolatzeko aukera gaituta daukan sare batera konektatzen den bakoitzean."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sare neurtua"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neurtu gabeko sarea"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Erregistroen buffer-tamainak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 39aacfd..b53a83d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"گواهینامه نمایش بیسیم"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"فعال کردن گزارشگیری طولانی Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"محدود کردن اسکن کردن Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"تصادفیسازی MAC غیرپایای Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"تصادفیسازی MAC غیرپایای Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"داده تلفن همراه همیشه فعال باشد"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"شتاب سختافزاری اشتراکگذاری اینترنت"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاههای بلوتوث بدون نام"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"تخلیه باتری راکاهش میدهد و عملکرد شبکه را بهبود میبخشد"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"اگر این حالت فعال باشد، هر بار این دستگاه به شبکهای متصل شود که تصادفیسازی MAC در آن فعال است، ممکن است نشانی MAC آن تغییر کند."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"اگر این حالت فعال باشد، هر بار این دستگاه به شبکهای متصل شود که تصادفیسازی MAC در آن فعال است، ممکن است نشانی MAC آن تغییر کند."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"محدودشده"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"محدودنشده"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"اندازههای حافظه موقت ثبتکننده"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index ca299f0..e116a19 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Langattoman näytön sertifiointi"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Käytä Wi-Fin laajennettua lokikirjausta"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-haun rajoitus"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"MAC-satunnaistaminen, jos Wi-Fi ei ole kiinteä"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"MAC-satunnaistaminen, jos Wi-Fi ei ole kiinteä"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiilidata aina käytössä"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Laitteistokiihdytyksen yhteyden jakaminen"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Vähentää virrankulutusta ja parantaa verkon toimintaa"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kun tämä tila on päällä, laitteen MAC-osoite voi muuttua aina, kun laite yhdistää verkkoon, jossa MAC-satunnaistaminen on käytössä"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kun tämä tila on päällä, laitteen MAC-osoite voi muuttua aina, kun laite yhdistää verkkoon, jossa MAC-satunnaistaminen on käytössä"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Maksullinen"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Maksuton"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Lokipuskurien koot"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index b503fdb..2291c6f 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser enreg. données Wi-Fi détaillées"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche de réseaux Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Réorganisation aléatoire MAC non persistante du Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Réorganisation aléatoire MAC non persistante du Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Données cellulaires toujours actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecte à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecte à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 921caba..3abd211 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Sélection aléatoire de l\'adresse MAC non persistante en Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Sélection aléatoire de l\'adresse MAC non persistante en Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quand ce mode est activé, l\'adresse MAC de cet appareil peut changer chaque fois qu\'il se connecte à un réseau Wi-Fi où le changement aléatoire d\'adresse MAC est activé"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quand ce mode est activé, l\'adresse MAC de cet appareil peut changer chaque fois qu\'il se connecte à un réseau Wi-Fi où le changement aléatoire d\'adresse MAC est activé."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 015f256..bbf8e74 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Activar rexistro detallado da wifi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación da busca de wifi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Orde aleatoria de enderezos MAC non persistentes para conexións wifi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Orde aleatoria de enderezos MAC non persistentes para conexións wifi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móbiles sempre activados"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware para conexión compartida"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opcións para o certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta o nivel de rexistro da wifi, móstrao por SSID RSSI no selector de wifi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce o consumo de batería e mellora o rendemento da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Cando este modo está activado, o enderezo MAC pode cambiar cada vez que se este dispositivo se conecta a unha rede que teña activada a orde aleatoria de enderezos MAC"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Cando este modo está activado, o enderezo MAC pode cambiar cada vez que se este dispositivo se conecta a unha rede que teña activada a orde aleatoria de enderezos MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Rede sen tarifa plana"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Rede con tarifa plana"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaño dos búfers do rexistrador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 8052e2a..9fc70cf 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -85,7 +85,7 @@
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"મીડિયા ઑડિયો"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ફોન કૉલ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ફાઇલ સ્થાનાંતરણ"</string>
- <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ઇનપુટ ઉપકરણ"</string>
+ <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ઇનપુટ ડિવાઇસ"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ઇન્ટરનેટ ઍક્સેસ"</string>
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"સંપર્ક શેરિંગ"</string>
<string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"સંપર્ક શેરિંગ માટે ઉપયોગ કરો"</string>
@@ -102,7 +102,7 @@
<string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"નકશા સાથે કનેક્ટ થયું"</string>
<string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"SAP થી કનેક્ટ કરેલ"</string>
<string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયેલ નથી"</string>
- <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"ઇનપુટ ઉપકરણ સાથે કનેક્ટ થયાં"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"ઇનપુટ ડિવાઇસ સાથે કનેક્ટ થયાં"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપકરણથી કનેક્ટેડ છીએ"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"ઉપકરણ સાથે સ્થાનિક ઇન્ટરનેટ કનેક્શન શેર કરી રહ્યાં છીએ"</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપયોગ કરો"</string>
@@ -155,7 +155,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"વપરાશકર્તા: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"કેટલાંક ડિફોલ્ટ્સ સેટ કરેલ છે"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"કોઈ ડિફૉલ્ટ સેટ કરેલા નથી"</string>
- <string name="tts_settings" msgid="8130616705989351312">"ટેક્સ્ટ-ટુ-સ્પીચ સેટિંગ્સ"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"ટેક્સ્ટ ટૂ સ્પીચ સેટિંગ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ટેક્સ્ટ ટુ સ્પીચ આઉટપુટ"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"વાણી દર"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"ટેક્સ્ટ બોલાયેલ છે તે ઝડપ"</string>
@@ -177,8 +177,8 @@
<string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> નેટવર્ક કનેક્શનની આવશ્યકતા છે"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> સમર્થિત નથી"</string>
<string name="tts_status_checking" msgid="8026559918948285013">"તપાસી રહ્યું છે..."</string>
- <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> માટેની સેટિંગ્સ"</string>
- <string name="tts_engine_settings_button" msgid="477155276199968948">"એન્જિન સેટિંગ્સ લોંચ કરો"</string>
+ <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> માટેના સેટિંગ"</string>
+ <string name="tts_engine_settings_button" msgid="477155276199968948">"એન્જિન સેટિંગ લૉન્ચ કરો"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"મનપસંદ એન્જિન"</string>
<string name="tts_general_section_title" msgid="8919671529502364567">"સામાન્ય"</string>
<string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"સ્પીચની પિચ ફરીથી સેટ કરો"</string>
@@ -201,9 +201,9 @@
<string name="development_settings_enable" msgid="4285094651288242183">"વિકાસકર્તાનાં વિકલ્પો સક્ષમ કરો"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ઍપ્લિકેશન વિકાસ માટે વિકલ્પો સેટ કરો"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"આ વપરાશકર્તા માટે વિકાસકર્તા વિકલ્પો ઉપલબ્ધ નથી"</string>
- <string name="vpn_settings_not_available" msgid="2894137119965668920">"આ વપરાશકર્તા માટે VPN સેટિંગ્સ ઉપલબ્ધ નથી"</string>
- <string name="tethering_settings_not_available" msgid="266821736434699780">"આ વપરાશકર્તા માટે ટિથરિંગ સેટિંગ્સ ઉપલબ્ધ નથી"</string>
- <string name="apn_settings_not_available" msgid="1147111671403342300">"અૅક્સેસ પોઇન્ટનું નામ સેટિંગ્સ આ વપરાશકર્તા માટે ઉપલબ્ધ નથી"</string>
+ <string name="vpn_settings_not_available" msgid="2894137119965668920">"આ વપરાશકર્તા માટે VPN સેટિંગ ઉપલબ્ધ નથી"</string>
+ <string name="tethering_settings_not_available" msgid="266821736434699780">"આ વપરાશકર્તા માટે ટિથરિંગ સેટિંગ ઉપલબ્ધ નથી"</string>
+ <string name="apn_settings_not_available" msgid="1147111671403342300">"અૅક્સેસ પૉઇન્ટનું નામ સેટિંગ આ વપરાશકર્તા માટે ઉપલબ્ધ નથી"</string>
<string name="enable_adb" msgid="8072776357237289039">"USB ડિબગીંગ"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"જ્યારે USB કનેક્ટ કરેલું હોય ત્યારે ડિબગ મોડ"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB ડીબગિંગ પ્રમાણીકરણોને રદબાતલ કરો"</string>
@@ -252,14 +252,15 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"વાયરલેસ ડિસ્પ્લે પ્રમાણન"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"વાઇ-ફાઇ વર્બોઝ લૉગિંગ ચાલુ કરો"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"વાઇ-ફાઇ સ્કૅનની ક્ષમતા મર્યાદિત કરવી"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"વાઇ-ફાઇ માટે સતત બદલાતું MAC રેન્ડમાઇઝેશન"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
+ <skip />
<string name="mobile_data_always_on" msgid="8275958101875563572">"મોબાઇલ ડેટા હંમેશાં સક્રિય"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ડિવાઇસ બતાવો"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ચોક્કસ વૉલ્યૂમને બંધ કરો"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ચાલુ કરો"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"બ્લૂટૂથ AVRCP વર્ઝન"</string>
- <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
+ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP વર્ઝન પસંદ કરો"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"બ્લૂટૂથ MAP વર્ઝન"</string>
<string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"બ્લૂટૂથ MAP વર્ઝન પસંદ કરો"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"બ્લૂટૂથ ઑડિયો કોડેક"</string>
@@ -284,7 +285,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"બૅટરીનો ચાર્જ ઝડપથી ઓછો થવાનું ટાળે છે અને નેટવર્કના કાર્યપ્રદર્શનમાં સુધારો કરે છે"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"આ મોડ ચાલુ કરેલો હશે, ત્યારે MAC રેન્ડમાઇઝેશન ચાલુ કરેલું હોય તેવા નેટવર્ક સાથે આ ડિવાઇસ જોડાશે ત્યારે દર વખતે તેનું MAC ઍડ્રેસ બદલાય તેમ બની શકે છે."</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"મીટર કરેલું"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"મીટર ન કરેલ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"લોગર બફર કદ"</string>
@@ -301,12 +303,12 @@
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"વાઇ-ફાઇ સક્રિય હોય ત્યારે પણ, હંમેશા મોબાઇલ ડેટાને સક્રિય રાખો (ઝડપી નેટવર્ક સ્વિચિંગ માટે)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"જો ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ ઉપલબ્ધ હોય તો તેનો ઉપયોગ કરો"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"USB ડિબગિંગને મંજૂરી આપીએ?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"USB ડિબગીંગ ફક્ત વિકાસ હેતુઓ માટે જ બનાવાયેલ છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ઉપકરણ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ઉપકરણ પર ઍપ્લિકેશનો ઇન્સ્ટોલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"USB ડિબગીંગ ફક્ત વિકાસ હેતુઓ માટે જ બનાવાયેલ છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ડિવાઇસ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ડિવાઇસ પર ઍપ ઇન્સ્ટોલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"વાયરલેસ ડિબગીંગને મંજૂરી આપીએ?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"વાયરલેસ ડિબગીંગ ફક્ત ડેવલપમેન્ટના હેતુઓ માટે જ બનાવાયું છે. તેનો ઉપયોગ તમારા કમ્પ્યુટર અને તમારા ડિવાઇસ વચ્ચે ડેટાને કૉપિ કરવા, નોટિફિકેશન વગર તમારા ડિવાઇસ પર ઍપને ઇન્સ્ટૉલ કરવા અને લૉગ ડેટા વાંચવા માટે કરો."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"તમે અગાઉ અધિકૃત કરેલા તમામ કમ્પ્યુટર્સમાંથી USB ડિબગિંગ પરની અૅક્સેસ રદબાતલ કરીએ?"</string>
- <string name="dev_settings_warning_title" msgid="8251234890169074553">"વિકાસ સેટિંગ્સને મંજૂરી આપીએ?"</string>
- <string name="dev_settings_warning_message" msgid="37741686486073668">"આ સેટિંગ્સ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ઉપકરણ અને તેના પરની એપ્લિકેશન્સનાં ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
+ <string name="dev_settings_warning_title" msgid="8251234890169074553">"ડેવલપમેન્ટ સેટિંગને મંજૂરી આપીએ?"</string>
+ <string name="dev_settings_warning_message" msgid="37741686486073668">"આ સેટિંગ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ડિવાઇસ અને તેના પરની ઍપના ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB પર ઍપ ચકાસો"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી ઍપ તપાસો."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"નામ વગરના (ફક્ત MAC ઍડ્રેસવાળા) બ્લૂટૂથ ડિવાઇસ બતાવવામાં આવશે"</string>
@@ -468,7 +470,7 @@
<string name="external_source_trusted" msgid="1146522036773132905">"મંજૂરી છે"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"મંજૂરી નથી"</string>
<string name="install_other_apps" msgid="3232595082023199454">"અજાણી ઍપ ઇન્સ્ટૉલ કરો"</string>
- <string name="home" msgid="973834627243661438">"સેટિંગ્સ હોમ"</string>
+ <string name="home" msgid="973834627243661438">"સેટિંગ હોમ"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
<item msgid="8894873528875953317">"50%"</item>
@@ -488,7 +490,7 @@
<string name="retail_demo_reset_title" msgid="1866911701095959800">"પાસવર્ડ આવશ્યક છે"</string>
<string name="active_input_method_subtypes" msgid="4232680535471633046">"ઇનપુટ પદ્ધતિઓ સક્રિય કરો"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"સિસ્ટમ ભાષાઓનો ઉપયોગ કરો"</string>
- <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> માટેની સેટિંગ્સ ખોલવામાં નિષ્ફળ"</string>
+ <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> માટેના સેટિંગ ખોલવામાં નિષ્ફળ"</string>
<string name="ime_security_warning" msgid="6547562217880551450">"આ ઇનપુટ પદ્ધતિ પાસવર્ડ્સ અને ક્રેડિટ કાર્ડ નંબર જેવી વ્યક્તિગત માહિતી સહિત તમે લખો છો તે તમામ ટેક્સ્ટ એકત્રિત કરવા માટે સક્ષમ હોઈ શકે છે. તે ઍપ્લિકેશન <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> માંથી આવે છે. આ ઇનપુટ પદ્ધતિ વાપરીએ?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"નોંધ: રીબૂટ કર્યાં પછી, જ્યાં સુધી તમે તમારો ફોન અનલૉક કરશો નહીં ત્યાં સુધી આ ઍપ્લિકેશન શરૂ થઈ શકશે નહીં"</string>
<string name="ims_reg_title" msgid="8197592958123671062">"IMS રજિસ્ટ્રેશનની સ્થિતિ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index bf9b72e..c065f9a 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिसप्ले सर्टिफ़िकेशन"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"वाई-फ़ाई वर्बोस लॉगिंग चालू करें"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"वाई-फ़ाई के लिए स्कैन की संख्या कम करें"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"थोड़े समय के लिए वाई-फ़ाई नेटवर्क से जुड़ने पर MAC पता बदलने की सुविधा"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"थोड़े समय के लिए वाई-फ़ाई नेटवर्क से जुड़ने पर MAC पता बदलने की सुविधा"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा हमेशा चालू"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिसप्ले सर्टिफ़िकेशन के विकल्प दिखाएं"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाई-फ़ाई लॉगिंग का स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बैटरी की खपत कम और नेटवर्क की परफ़ॉर्मेंस बेहतर होती है"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"जब यह मोड चालू होता है, तब नेटवर्क से कनेक्ट होने पर हर बार इस डिवाइस का मैक पता बदल सकता है. ऐसा तब होता है, जब डिवाइस किसी ऐसे नेटवर्क से जुड़ता है जिस पर मैक पते को बिना किसी तय नियम के बदलने की सुविधा चालू होती है."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"जब यह मोड चालू होता है, तब नेटवर्क से कनेक्ट होने पर हर बार इस डिवाइस का MAC पता बदल सकता है. ऐसा तब होता है, जब डिवाइस किसी ऐसे नेटवर्क से जुड़ता है जिस पर MAC पता बदलने की सुविधा चालू होती है."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"डेटा इस्तेमाल करने की सीमा तय की गई है"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"डेटा इस्तेमाल करने की सीमा तय नहीं की गई है"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफ़र आकार"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 51884f3..0727c83 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući opširnu prijavu na Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje traženja Wi-Fija"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nasumični odabir nepostojane MAC adrese za Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumični odabir nepostojane MAC adrese za Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci uvijek aktivni"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje za modemsko povezivanje"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava rad mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je omogućen ovaj način, MAC adresa ovog uređaja može se promijeniti svaki put kad se uređaj poveže s mrežom na kojoj je omogućen nasumični odabir MAC-a."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je omogućen ovaj način, MAC adresa ovog uređaja može se promijeniti svaki put kad se uređaj poveže s mrežom na kojoj je omogućen nasumični odabir MAC-a."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"S ograničenim prometom"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja prometa"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međuspremnika zapisnika"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 8fc854c..12a81a6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Vezeték nélküli kijelző tanúsítványa"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Részletes Wi-Fi-naplózás engedélyezése"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi-hálózat szabályozása"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi nem állandó MAC-randomizációja"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi nem állandó MAC-randomizációja"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"A mobilhálózati kapcsolat mindig aktív"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Internetmegosztás hardveres gyorsítása"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Csökkenti az akkumulátorhasználatot, és javítja a hálózat teljesítményét"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ha ez a mód be van kapcsolva, akkor ennek az eszköznek a MAC-címe minden alkalommal módosulhat, amikor olyan hálózathoz csatlakozik, amelyen engedélyezve van a MAC-címek randomizálása."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ha ez a mód be van kapcsolva, akkor ennek az eszköznek a MAC-címe minden alkalommal módosulhat, amikor olyan hálózathoz csatlakozik, amelyen engedélyezve van a MAC-címek randomizálása."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Forgalomkorlátos"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Nem forgalomkorlátos"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Naplózási puffer mérete"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 766eb38..1fd6c5f 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Անլար էկրանների հավաստագրում"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Միացնել Wi‑Fi մանրամասն գրանցամատյանները"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-ի որոնման սահմանափակում"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Պատահական հերթականությամբ դասավորված MAC հասցեներ Wi‑Fi ցանցում"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Պատահական հերթականությամբ դասավորված MAC հասցեներ Wi‑Fi ցանցում"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Բջջային ինտերնետը միշտ ակտիվ է"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Սարքակազմի արագացման միացում"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ցույց տալ անլար էկրանների հավաստագրման ընտրանքները"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Նվազեցնում է մարտկոցի սպառումը և լավացնում ցանցի աշխատանքը"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Երբ այս ռեժիմը միացված է, MAC հասցեն կարող է փոխվել ամեն անգամ, երբ սարքը միանա որևէ ցանցի, որում միացված է MAC հասցեների պատահական ընտրությունը։"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Երբ այս ռեժիմը միացված է, MAC հասցեն կարող է փոխվել ամեն անգամ, երբ սարքը միանա որևէ ցանցի, որում միացված է MAC հասցեների պատահական ընտրությունը։"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Վճարովի թրաֆիկ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Անսահմանափակ թրաֆիկ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Մատյանի բուֆերի չափերը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 4b37650..3480411 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktifkan Pencatatan Log Panjang Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Pembatasan pemindaian Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Pengacakan MAC nonpersisten Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Pengacakan tidak tetap MAC Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Data seluler selalu aktif"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Akselerasi hardware tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Memperlambat kehabisan baterai & meningkatkan performa jaringan"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Saat mode ini diaktifkan, alamat MAC perangkat ini dapat berubah setiap kali terhubung ke jaringan yang mengaktifkan pengacakan MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Jika mode ini diaktifkan, alamat MAC perangkat ini dapat berubah setiap kali terhubung ke jaringan yang mengaktifkan pengacakan MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Berbayar"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak berbayar"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Ukuran buffer pencatat log"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 9b08303..8b56f6a 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Kveikja á ítarlegri skráningu Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Hægja á Wi‑Fi leit"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Slembiröðun tímabundinna MAC-vistfanga um Wi-Fi tengingu"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Slembiröðun tímabundinna MAC-vistfanga um Wi-Fi tengingu"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Alltaf kveikt á farsímagögnum"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Vélbúnaðarhröðun fyrir tjóðrun"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Dregur úr rafhlöðunotkun og eykur netafköst"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Þegar kveikt er á þessari stillingu gæti MAC-vistfang þessa tækis breyst í hvert sinn sem það tengist neti sem er með kveikt á slembivali MAC-vistfanga."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Þegar kveikt er á þessari stillingu gæti MAC-vistfang þessa tækis breyst í hvert sinn sem það tengist neti sem er með kveikt á slembivali MAC-vistfanga."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mæld notkun"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Notkun ekki mæld"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Annálsritastærðir biðminna"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index b3bdf89..def0909 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificazione display wireless"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Attiva logging dettagliato Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limita ricerca di reti Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Randomizzazione indirizzi MAC non persistenti per connessione a reti Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizzazione non persistente dell\'indirizzo MAC Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dati mobili sempre attivi"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering accelerazione hardware"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta livello di logging Wi-Fi, mostra SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Riduce il consumo della batteria e migliora le prestazioni della rete"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che si connette a una rete con randomizzazione MAC attivata"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che il dispositivo si connette a una rete con randomizzazione degli indirizzi MAC attiva."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"A consumo"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non a consumo"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Dimensioni buffer logger"</string>
@@ -444,7 +444,7 @@
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Il telefono potrebbe spegnersi a breve"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Il tablet potrebbe spegnersi a breve"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Il dispositivo potrebbe spegnersi a breve"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 71cc9a0..fba3aeb 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"אישור של תצוגת Wi-Fi"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"הפעלת רישום מפורט של Wi‑Fi ביומן"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ויסות סריקה לנקודות Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"רנדומיזציה של כתובות MAC בלי חיבור יציב ל-Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"רנדומיזציה של כתובות MAC בלי חיבור יציב ל-Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"חבילת הגלישה פעילה תמיד"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"הצגת מכשירי Bluetooth ללא שמות"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"הצגת אפשרויות עבור אישור של תצוגת Wi-Fi"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"העלאת רמת הרישום של Wi‑Fi ביומן, הצגה לכל SSID RSSI ב-Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"אפשרות זו מפחיתה את קצב התרוקנות הסוללה ומשפרת את ביצועי הרשת"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"כשמצב זה מופעל, כתובת ה-MAC של המכשיר הזה עשויה להשתנות בכל פעם שהוא מתחבר לרשת שפועלת בה רנדומיזציה של כתובות MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"כשהמצב הזה מופעל, כתובת ה-MAC של המכשיר הזה יכולה להשתנות בכל פעם שהוא מתחבר לרשת שבה פועלת רנדומיזציה של כתובות MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"חיוב לפי שימוש בנתונים"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"לא נמדדת"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"גודלי מאגר של יומן רישום"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index dd3b00b..1a7d9ba 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ワイヤレス ディスプレイ認証"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi 詳細ログの有効化"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi スキャン スロットリング"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi-Fi 非永続的 MAC ランダム化"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi-Fi 非永続的 MAC ランダム化"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"モバイルデータを常に ON にする"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"テザリング時のハードウェア アクセラレーション"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ワイヤレス ディスプレイ認証のオプションを表示"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ログレベルを上げて、Wi-Fi 選択ツールで SSID RSSI ごとに表示します"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"電池の消耗が軽減され、ネットワーク パフォーマンスが改善されます"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ON にすると、MAC アドレスのランダム化が有効なネットワークに接続するたびに、このデバイスの MAC アドレスが変わる可能性があります。"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ON にすると、MAC アドレスのランダム化が有効なネットワークに接続するたびに、このデバイスの MAC アドレスが変わる可能性があります。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"従量制"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"定額制"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ログバッファのサイズ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 6f023e9..33d3e65 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"უსადენო ეკრანის სერტიფიცირება"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi-ს დაწვრილებითი აღრიცხვის ჩართვა"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi სკანირების რეგულირება"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi-ს MAC მისამართების არამუდმივი რანდომიზაცია"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi-ის MAC მისამართების არამუდმივი რანდომიზაცია"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"მობილური ინტერნეტის ყოველთვის გააქტიურება"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ტეტერინგის აპარატურული აჩქარება"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ამცირებს ბატარეის ხარჯვას და აუმჯობესებს ქსელის მუშაობას"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"როდესაც ეს რეჟიმი ჩართულია, მოწყობილობის MAC მისამართი შეიძლება შეიცვალოს ისეთ ქსელთან ყოველ დაკავშირებაზე, რომელსაც ჩართული აქვს MAC მისამართის შემთხვევითობა."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"როდესაც ეს რეჟიმი ჩართულია, ამ მოწყობილობის MAC მისამართი შეიძლება შეიცვალოს ისეთ ქსელთან ყოველ დაკავშირებაზე, რომელსაც ჩართული აქვს MAC მისამართის რანდომიზაცია."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ლიმიტირებული"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"არალიმიტირებული"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ჟურნალიზაციის ბუფერის ზომები"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 2fbe33e..62dff735 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Сымсыз дисплей сертификаты"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Толық мәліметті Wi‑Fi журналы"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi желілерін іздеуді шектеу"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi желісінің тұрақсыз MAC рандомизациясы"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi желісінің тұрақсыз MAC рандомизациясы"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мобильдік интернет әрқашан қосулы"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Тетеринг режимінде аппаратпен жеделдету"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Сымсыз дисплей сертификаты опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi тіркеу деңгейін арттыру, Wi‑Fi таңдағанда әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарея зарядының шығынын азайтады және желі жұмысын жақсартады."</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Бұл режим қосулы болса, құрылғының MAC мекенжайы MAC рандомизациясы қосулы желіге жалғанған сайын өзгеруі мүмкін."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Бұл режим қосулы болса, құрылғының MAC мекенжайы MAC рандомизациясы қосулы желіге жалғанған сайын өзгеруі мүмкін."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Трафик саналатын желі"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Трафик саналмайды"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферінің өлшемдері"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index f2ab2f8..0b23e68 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"បើកកំណត់ហេតុរៀបរាប់ Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ការពន្យឺតការស្កេន Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"ការតម្រៀប MAC ដែលមិនមានលក្ខណៈជាប់លាប់តាមលំដាប់ចៃដន្យនៃ Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ការតម្រៀប MAC ដែលមិនមានលក្ខណៈជាប់លាប់តាមលំដាប់ចៃដន្យនៃ Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ទិន្នន័យទូរសព្ទចល័តដំណើរការជានិច្ច"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ការពន្លឿនល្បឿនភ្ជាប់ដោយប្រើហាតវែរ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញឧបករណ៍ប្ល៊ូធូសគ្មានឈ្មោះ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"បង្ហាញជម្រើសសម្រាប់សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"បង្កើនកម្រិតកំណត់ហេតុ Wi-Fi បង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសរើស Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"កាត់បន្ថយការប្រើប្រាស់ថ្ម និងកែលម្អប្រតិបត្តិការបណ្ដាញ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"នៅពេលបើកមុខងារនេះ អាសយដ្ឋាន MAC របស់ឧបករណ៍នេះអាចផ្លាស់ប្ដូរ រាល់ពេលដែលវាភ្ជាប់ជាមួយបណ្ដាញដែលបានបើកការប្រើ MAC ចៃដន្យ។"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"នៅពេលបើកមុខងារនេះ អាសយដ្ឋាន MAC របស់ឧបករណ៍នេះអាចផ្លាស់ប្ដូរ រាល់ពេលដែលវាភ្ជាប់ជាមួយបណ្ដាញដែលបានបើកការប្រើ MAC ចៃដន្យ។"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"មានការកំណត់"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"មិនមានការកំណត់"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ទំហំឡុកជើបាហ្វើ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index c4ba449..99fd1d3 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -252,7 +252,8 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi ವೆರ್ಬೋಸ್ ಲಾಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ವೈ-ಫೈ ಸ್ಕ್ಯಾನ್ ನಿರ್ಬಂಧಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"ವೈ-ಫೈ ನಿರಂತರವಲ್ಲದ MAC ಯಾದೃಚ್ಛಿಕರಣ"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
+ <skip />
<string name="mobile_data_always_on" msgid="8275958101875563572">"ಮೊಬೈಲ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ಟೆಥರಿಂಗ್ಗಾಗಿ ಹಾರ್ಡ್ವೇರ್ ವೇಗವರ್ಧನೆ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
@@ -284,7 +285,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ಬ್ಯಾಟರಿ ಹೆಚ್ಚು ಬಾಳಿಕೆ ಬರುವಂತೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ನೆಟ್ವರ್ಕ್ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸುತ್ತದೆ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ಈ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, ಪ್ರತಿ ಬಾರಿ MAC ಯಾದೃಚ್ಛಿಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿದಾಗ ಈ ಸಾಧನದ MAC ವಿಳಾಸವು ಬದಲಾಗಬಹುದು."</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"ಮೀಟರ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ಮೀಟರ್ ಮಾಡಲಾಗಿಲ್ಲ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ಲಾಗರ್ ಬಫರ್ ಗಾತ್ರಗಳು"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 97ad0a0..421c60f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"무선 디스플레이 인증서"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi 상세 로깅 사용"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 검색 제한"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi 비지속적인 MAC 주소 무작위 순서 지정"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 비지속적인 MAC 주소 무작위 순서 지정"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"항상 모바일 데이터 활성화"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"테더링 하드웨어 가속"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"무선 디스플레이 인증서 옵션 표시"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"배터리 소모를 줄이고 네트워크 성능 개선"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"이 모드를 사용 설정하면 기기가 MAC 주소 무작위 지정이 설정된 네트워크에 연결될 때마다 기기의 MAC 주소가 변경될 수 있습니다."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"이 모드를 사용 설정하면 기기가 MAC 주소 무작위 지정이 설정된 네트워크에 연결될 때마다 기기의 MAC 주소가 변경될 수 있습니다."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"종량제 네트워크"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"무제한 네트워크"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"로거 버퍼 크기"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index b1aee50..bdc4939 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Зымсыз мониторлорду тастыктамалоо"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi таржымалы"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi тармактарын издөөнү жөнгө салуу"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi туташуусу туруксуз MAC даректерин башаламан түзүү"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi туташуусу туруксуз MAC даректерин башаламан иретте түзүү"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилдик Интернет иштей берет"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем режиминде аппараттын иштешин тездетүү"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрүнсүн"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Зымсыз мониторлорду тастыктамалоо параметрлери көрүнүп турат"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi тандалганда ар бир SSID үчүн RSSI көрүнүп турат"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батареяны үнөмдөп, тармактын иштешин жакшыртат"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Бул режим өчүрүлгөндөн кийин түзмөк MAC даректи башаламан иретте түзүү функциясы иштетилген тармакка туташкан сайын анын MAC дареги өзгөрүшү мүмкүн."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Бул режим өчүрүлгөндөн кийин, түзмөк MAC дарегин башаламан иретте түзүү функциясы иштетилген тармакка туташкан сайын анын MAC дареги өзгөрүшү мүмкүн."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Трафик ченелет"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Чектелбеген тармак"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферинин өлчөмү"</string>
@@ -309,7 +309,7 @@
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Орнотулуучу колдонмону текшерүү"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT аркылуу орнотулган колдонмолордун коопсуздугу текшерилет."</string>
- <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрсөтүлөт"</string>
+ <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрүнөт"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Алыскы түзмөктөр өтө катуу добуш чыгарып же көзөмөлдөнбөй жатса Bluetooth \"Үндүн абсолюттук деңгээли\" функциясын өчүрөт."</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Bluetooth Gabeldorsche функциясынын топтомун иштетет."</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Жакшыртылган туташуу функциясын иштетет."</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 462b53f..91e5c00 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ສະແດງການຮັບຮອງຂອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"ເປີດນຳໃຊ້ການເກັບປະຫວັດ Verbose Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ການຈຳກັດການສະແກນ Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"ການສຸ່ມ MAC ທີ່ມີ Wi-Fi ບໍ່ຖາວອນ"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ການສຸ່ມ MAC ທີ່ມີ Wi-Fi ແບບບໍ່ຖາວອນ"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືຕະຫຼອດເວລາ"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ຫຼຸດການໃຊ້ແບັດເຕີຣີ ແລະ ປັບປຸງປະສິດທິພາບເຄືອຂ່າຍ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ຫາກເປີດການນຳໃຊ້ໂໝດນີ້, ທີ່ຢູ່ MAC ຂອງອຸປະກອນນີ້ອາດມີການປ່ຽນແປງໃນແຕ່ລະເທື່ອທີ່ມັນເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍໃດໜຶ່ງທີ່ເປີດການນຳໃຊ້ການສຸ່ມ MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ຫາກເປີດການນຳໃຊ້ໂໝດນີ້, ທີ່ຢູ່ MAC ຂອງອຸປະກອນນີ້ອາດມີການປ່ຽນແປງໃນແຕ່ລະເທື່ອທີ່ມັນເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍໃດໜຶ່ງທີ່ເປີດການນຳໃຊ້ການສຸ່ມ MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ມີການວັດແທກ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ບໍ່ໄດ້ວັດແທກ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ຂະໜາດບັບເຟີຕົວບັນທຶກ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 491a082..9887a93 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Belaidžio rodymo sertifikavimas"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Įgal. „Wi‑Fi“ daugiaž. įraš. į žurnalą"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"„Wi‑Fi“ nuskaitymo ribojimas"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"MAC atsitiktinis parinkimas esant nepastoviam „Wi‑Fi“"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"MAC atsitiktinis parinkimas esant nepastoviam „Wi‑Fi“"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiliojo ryšio duomenys visada suaktyvinti"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sumažinamas akumuliatoriaus eikvojimas ir patobulinamas tinklo našumas"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kai įgalintas šis režimas, šio įrenginio MAC adresas gali keistis kas kartą prisijungus prie tinklo, kuriame įgalintas atsitiktinis MAC parinkimas."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kai įgalintas šis režimas, šio įrenginio MAC adresas gali keistis kas kartą prisijungus prie tinklo, kuriame įgalintas atsitiktinis MAC parinkimas."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Matuojamas"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neišmatuotas"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Registruotuvo buferio dydžiai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 9fcc749..81a566c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Bezvadu attēlošanas sertifikācija"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Iespējot Wi‑Fi detalizēto reģistrēšanu"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi meklēšanas ierobežošana"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nepastāvīgu MAC adrešu nejauša izveide Wi-Fi savienojumiem"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nepastāvīgu MAC adrešu nejauša izveide Wi-Fi savienojumiem"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Vienmēr aktīvs mobilo datu savienojums"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Paātrināta aparatūras darbība piesaistei"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Samazina akumulatora izlādi un uzlabo tīkla veiktspēju"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ja šis režīms ir iespējots, šīs ierīces MAC adrese var mainīties ikreiz, kad ierīcē tiek izveidots savienojums ar tīklu, kurā ir iespējota MAC adrešu nejauša izveide."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ja šis režīms ir iespējots, šīs ierīces MAC adrese var mainīties ikreiz, kad ierīcē tiek izveidots savienojums ar tīklu, kurā ir iespējota MAC adrešu nejauša izveide."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Maksas"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bezmaksas"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Reģistrētāja buferu lielumi"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f1f1639..ed64960 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Приказ на сертификација на безжична мрежа"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Овозможи преопширно пријавување Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Регулирање на скенирањето за Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Непостојана MAC-рандомизација на Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Непостојана MAC-рандомизација на Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилниот интернет е секогаш активен"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско забрзување за врзување"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Покажи ги опциите за безжичен приказ на сертификат"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Го намалува искористувањето на батеријата и ја подобрува изведбата на мрежата"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Кога е овозможен режимов, MAC-адресата на уредов може да се промени секој пат кога ќе се поврзе со мрежа што има овозможена рандомизација на MAC-адреси."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Кога е овозможен режимов, MAC-адресата на уредов може да се промени секој пат кога ќе се поврзе со мрежа што има овозможена MAC-рандомизација."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Со ограничен интернет"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничен интернет"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Величини на меѓумеморија за дневникот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index bf241c3..660f4b6 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷൻ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"വൈഫൈ വെർബോസ് ലോഗിംഗ് പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"വൈഫൈ സ്കാൻ ത്രോട്ടിലിംഗ്"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"വൈഫൈ വഴിയുള്ള, സ്ഥിരതയില്ലാത്ത MAC ക്രമരഹിതമാക്കൽ"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"വൈഫൈ വഴിയുള്ള, സ്ഥിരതയില്ലാത്ത MAC ക്രമരഹിതമാക്കൽ"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"മൊബൈൽ ഡാറ്റ എല്ലായ്പ്പോഴും സജീവം"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ടെതറിംഗ് ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തൽ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ബാറ്ററി ചാർജ് വേഗത്തിൽ തീരുന്ന അവസ്ഥ കുറച്ച് നെറ്റ്വർക്ക് പ്രകടനം മെച്ചപ്പെടുത്തുന്നു"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ഈ മോഡ് പ്രവർത്തനക്ഷമമാക്കുമ്പോൾ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുമ്പോഴെല്ലാം ഈ ഉപകരണത്തിന്റെ MAC വിലാസം മാറിയേക്കാം."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ഈ മോഡ് പ്രവർത്തനക്ഷമമാക്കുമ്പോൾ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുമ്പോഴെല്ലാം ഈ ഉപകരണത്തിന്റെ MAC വിലാസം മാറിയേക്കാം."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർ ചെയ്തത്"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"മീറ്റർമാപകമല്ലാത്തത്"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ലോഗർ ബഫർ വലുപ്പം"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 5ac22ff..074b864 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -155,8 +155,8 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Хэрэглэгч: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Зарим үндсэн тохиргоонуудыг суулгасан"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Ямар ч үндсэн тохиргоог суулгаагүй байна"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Текст-ярианы тохиргоо"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"Текстийг яриа болгон гаргах"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Бичвэрийг ярианд хувиргах тохиргоо"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"Бичвэрийг ярианд хувиргах"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Ярианы түвшин"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Текстийг унших хурд"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Авиа тон"</string>
@@ -170,7 +170,7 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"Хоолойн өгөгдлийг суулгах"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"Яриа үүсгэхэд шаардлагатай дууны өгөгдлийг суулгах"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Энэ яриа үүсгүүр нь нууц үг, зээлийн картын дугаар гэх мэт таны хувийн мэдээллийг оруулан унших бүх текстийг цуглуулах боломжтой. Үүнийг <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> үүсгүүрээс нийлүүлдэг. Энэ яриа үүсгүүрийн ашиглалтыг идэвхжүүлэх үү?"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"Энэ хэл нь текстээс дуунд хөрвүүлэхэд ажлын сүлжээний холболтыг шаарддаг."</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"Энэ хэл нь бичвэрийг ярианд хувиргахад ажлын сүлжээний холболт шаардана."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Энэ бол яриа үүсгэх жишээ юм."</string>
<string name="tts_status_title" msgid="8190784181389278640">"Үндсэн хэлний статус"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> бүрэн дэмжигдсэн"</string>
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Утасгүй дэлгэцийн сертификат"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi дэлгэрэнгүй лог-г идэвхжүүлэх"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi скан бууруулалт"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi-н байнгын бус MAC-г санамсаргүй байдлаар эмхлэх"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi-н байнгын бус MAC-г санамсаргүй байдлаар эмхлэх"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мобайл дата байнга идэвхтэй"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем болгох техник хангамжийн хурдасгуур"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi логийн түвшнийг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарей зарцуулалтыг бууруулж, сүлжээний гүйцэтгэлийг сайжруулдаг"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Энэ горимыг идэвхжүүлсэн үед энэ төхөөрөмжийг MAC-н санамсаргүй байдлаар эмхлэх явцыг идэвхжүүлсэн сүлжээнд холбогдох бүрд үүний MAC хаягийг өөрчилж болзошгүй."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Энэ горимыг идэвхжүүлсэн үед энэ төхөөрөмжийг MAC-н санамсаргүй байдлаар эмхлэх явцыг идэвхжүүлсэн сүлжээнд холбогдох бүрд үүний MAC хаягийг өөрчилж болзошгүй."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Хязгаартай"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Хязгааргүй"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Логгерын буферын хэмжээ"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 864f177..0b0a4a6 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -252,7 +252,8 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रमाणीकरण"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"वाय-फाय व्हर्बोझ लॉगिंग सुरू करा"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"वाय-फाय स्कॅन थ्रॉटलिंग"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"वाय-फायचे सातत्याने न होणारे MAC रँडमायझेशन"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
+ <skip />
<string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा नेहमी सक्रिय"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिंग हार्डवेअर अॅक्सिलरेशन"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्लूटूथ डिव्हाइस दाखवा"</string>
@@ -284,7 +285,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय सिलेक्टरमध्ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बॅटरी जलदरीतीने संपण्यापासून रोखते आणि नेटवर्क परफॉर्मन्समध्ये सुधारणा करते"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"हा मोड सुरू केला असल्यास, या डिव्हाइसचा MAC अॅड्रेस प्रत्येक वेळी MAC रँडमायझेशन सुरू असलेल्या नेटवर्कशी कनेक्ट झाल्यास, कदाचित बदलू शकतो."</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"मीटरने मोजलेले"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मीटरने न मोजलेले"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफर आकार"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 5ed5f39..4390896 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Dayakan Pengelogan Berjela-jela Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Pendikitan pengimbasan Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Perawakan MAC tidak berterusan Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Perawakan MAC tidak berterusan Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Data mudah alih sentiasa aktif"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Pecutan perkakasan penambatan"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Mengurangkan penyusutan bateri & meningkatkan prestasi rangkaian"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Apabila mod ini didayakan, alamat MAC peranti ini mungkin berubah setiap kali peranti bersambung kepada rangkaian yang telah mendayakan perawakan MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Apabila mod ini didayakan, alamat MAC peranti ini mungkin berubah pada setiap kali peranti menyambung kepada rangkaian yang telah mendayakan perawakan MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Bermeter"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak bermeter"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Saiz penimbal pengelog"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2f57106..199d15c 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ကြိုးမဲ့ပြသမှု အသိအမှတ်ပြုလက်မှတ်"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Verbose မှတ်တမ်းတင်ခြင်းအား ဖွင့်မည်"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ရှာဖွေခြင်း ထိန်းချုပ်မှု"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi ပြောင်းလဲသော MAC ကျပန်းပြုလုပ်ခြင်း"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi ပြောင်းလဲသော MAC ကျပန်းပြုလုပ်ခြင်း"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"မိုဘိုင်းဒေတာကို အမြဲဖွင့်ထားရန်"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ဘက်ထရီ အသုံးပြုမှုကို လျှော့ကျစေပြီး ကွန်ရက်စွမ်းဆောင်ရည်ကို ပိုမိုကောင်းမွန်စေသည်"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ဤမုဒ်ကို ဖွင့်ထားသည့်အခါ MAC ကျပန်းပြုလုပ်ထားသည့် ကွန်ရက်သို့ ချိတ်ဆက်လိုက်သည့်အခါတိုင်း ဤစက်၏ MAC လိပ်စာ ပြောင်းသွားပါမည်။"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ဤမုဒ်ကို ဖွင့်ထားသည့်အခါ MAC ကျပန်းပြုလုပ်ထားသည့် ကွန်ရက်သို့ ချိတ်ဆက်လိုက်သည့်အခါတိုင်း ဤစက်၏ MAC လိပ်စာ ပြောင်းသွားနိုင်သည်။"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"အခမဲ့ မဟုတ်ပါ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"အခမဲ့"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"မှတ်တမ်းကြားခံနယ် အရွယ်အစားများ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f39c0dc..722f98f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Trådløs skjerm-sertifisering"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Slå på detaljert Wi-Fi-loggføring"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrensning av Wi‑Fi-skanning"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Ikke-vedvarende tilfeldiggjøring av MAC-adresse for Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ikke-vedvarende tilfeldiggjøring av MAC-adresse for Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er alltid aktiv"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvareakselerasjon for internettdeling"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis alternativer for sertifisering av trådløs skjerm"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk nivået av Wi-Fi-logging – vis per SSID RSSI i Wi-Fi-velgeren"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduserer batteriforbruket og forbedrer nettverksytelsen"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Når denne modusen er slått på, kan MAC-adressen til denne enheten endres hver gang den kobler seg til et nettverk som har tilfeldiggjøring av MAC-adresse slått på."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Når denne modusen er slått på, kan MAC-adressen til denne enheten endres hver gang den kobler seg til et nettverk som har tilfeldiggjøring av MAC-adresse slått på."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Med datamåling"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Uten datamåling"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Bufferstørrelser for logg"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index bb94c24..a109c58 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रयोग गर्ने वा नगर्ने"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi भर्बोज लग अन गरियोस्"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi स्क्यान थ्रोटलिङ"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi-Fi नन्-पर्सिस्टेन्ट MAC र्यान्डमाइजेसन"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi-Fi नन-पर्सिस्टेन्ट MAC र्यान्डमाइजेसन"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा सधैँ अन होस्"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ डिभाइस देखाइयोस्"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्लेसम्बन्धी विकल्प देखाइयोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi लगिङ लेभल बढाइयोस्, Wi-Fi पिकरमा प्रति SSID RSSI देखाइयोस्"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"यसले ब्याट्रीको खपत कम गर्छ र नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"यो मोड अन गरिएका बेला यो डिभाइस MAC एड्रेस बदल्ने सुविधा अन गरिएको नेटवर्कमा जति पटक कनेक्ट हुन्छ त्यति नै पटक यस डिभाइसको MAC एड्रेस पनि परिवर्तन हुन सक्छ।"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"यो मोड अन गरिएका बेला यो डिभाइस MAC एड्रेस बदल्ने सुविधा अन गरिएको नेटवर्कमा जति पटक कनेक्ट हुन्छ त्यति नै पटक यस डिभाइसको MAC एड्रेस पनि परिवर्तन हुन सक्छ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मिटर नगरिएको"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लगर बफरका आकारहरू"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 017de6a..12a47bc 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Uitgebreide wifi-logregistr. aanzetten"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-scannen beperken"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Niet-persistente MAC-herschikking in willekeurige volgorde voor wifi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Niet-persistente MAC-herschikking in willekeurige volgorde voor wifi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data altijd actief"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareversnelling voor tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder naam tonen"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Toon opties voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog het logniveau voor wifi, toon per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag het batterijverbruik en verbeter de netwerkprestaties"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Als deze modus aanstaat, kan het MAC-adres van dit apparaat veranderen telkens als het apparaat verbinding maakt met een netwerk waarvoor MAC-herschikking aanstaat."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Als dit aanstaat, kan het MAC-adres van dit apparaat veranderen telkens als het apparaat verbinding maakt met een netwerk waarvoor MAC-herschikking aanstaat."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Met datalimiet"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Gratis"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-buffergrootten"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index c885c16..d047b17 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ୱାୟରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"ୱାଇ-ଫାଇ ଭର୍ବୋସ୍ ଲଗିଙ୍ଗ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ୱାଇ-ଫାଇ ସ୍କାନ୍ ନିୟନ୍ତ୍ରଣ"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"ୱାଇ-ଫାଇ ଅଣ-ଅବିରତ MAC ରେଣ୍ଡମାଇଜେସନ୍"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ୱାଇ-ଫାଇ ଅଣ-ଅବିରତ MAC ରେଣ୍ଡମାଇଜେସନ୍"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ମୋବାଇଲ୍ ଡାଟା ସର୍ବଦା ସକ୍ରିୟ"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର ଆକ୍ସିଲିରେସନ୍"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍ ଡିଭାଇସ୍ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ୱେୟାରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ଯେତେବେଳେ ଏହି ମୋଡ୍ ସକ୍ଷମ ହୁଏ, ପ୍ରତ୍ୟେକ ଥର MAC ରେଣ୍ଡୋମାଇଜେସନ୍ ସକ୍ଷମ ଥିବା କୌଣସି ନେଟୱାର୍କ ସହ ଏହି ଡିଭାଇସ୍ ସଂଯୋଗ ହେଲେ ଏହାର MAC ଠିକଣା ବଦଳିପାରେ।"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ଯେତେବେଳେ ଏହି ମୋଡ୍ ସକ୍ଷମ କରାଯାଏ, ପ୍ରତ୍ୟେକ ଥର MAC ରେଣ୍ଡୋମାଇଜେସନ୍ ସକ୍ଷମ ଥିବା କୌଣସି ନେଟୱାର୍କ ସହ ଏହି ଡିଭାଇସ୍ ସଂଯୋଗ ହେଲେ ଏହାର MAC ଠିକଣା ବଦଳିପାରେ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ମପାଯାଉଥିବା"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ମପାଯାଉନଥିବା"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ଲଗର୍ ବଫର୍ ସାଇଜ୍"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 127f571..a310dae 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"ਵਾਈ-ਫਾਈ ਵਰਬੋਸ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"ਵਾਈ‑ਫਾਈ ਸਕੈਨ ਥਰੌਟਲਿੰਗ"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"ਵਾਈ-ਫਾਈ ਲਈ ਗੈਰ-ਸਥਾਈ MAC ਬੇਤਰਤੀਬਵਾਰ"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ਵਾਈ-ਫਾਈ ਲਈ ਗੈਰ-ਸਥਾਈ MAC ਬੇਤਰਤੀਬਵਾਰ"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ ਚੋਣਕਾਰ ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਘਟਾ ਕੇ ਨੈੱਟਵਰਕ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਂਦਾ ਹੈ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ਜਦੋਂ ਇਹ ਮੋਡ ਚਾਲੂ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਇਸ ਡੀਵਾਈਸ ਦਾ MAC ਪਤਾ ਹਰ ਵਾਰ ਬਦਲ ਸਕਦਾ ਹੈ ਜਦੋਂ ਇਹ ਕਿਸੇ ਅਜਿਹੇ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ MAC ਦਾ ਬੇਤਰਤੀਬੀਕਰਨ ਚਾਲੂ ਹੁੰਦਾ ਹੈ।"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ਜਦੋਂ ਇਹ ਮੋਡ ਚਾਲੂ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਇਸ ਡੀਵਾਈਸ ਦਾ MAC ਪਤਾ ਹਰ ਵਾਰ ਬਦਲ ਸਕਦਾ ਹੈ ਜਦੋਂ ਇਹ ਕਿਸੇ ਅਜਿਹੇ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ MAC ਬੇਤਰਤੀਬਵਾਰ ਚਾਲੂ ਹੁੰਦਾ ਹੈ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ਗੈਰ-ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ਲੌਗਰ ਬਫ਼ਰ ਆਕਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index db621be..22b0539 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -247,7 +247,7 @@
<item msgid="5023908510820531131">"W: <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
</string-array>
<string-array name="debug_hw_overdraw_entries">
- <item msgid="1968128556747588800">"Wył."</item>
+ <item msgid="1968128556747588800">"Wyłączone"</item>
<item msgid="3033215374382962216">"Pokaż przerysowywane obszary"</item>
<item msgid="3474333938380896988">"Pokaż obszary dostosowane do deuteranomalii"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index fea9601..011c895 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certyfikacja wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Szczegółowy dziennik Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Ograniczanie skanowania Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Nietrwała randomizacja adresów MAC w sieci Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nietrwała randomizacja adresów MAC w sieci Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilna transmisja danych zawsze aktywna"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Akceleracja sprzętowa tetheringu"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokazuj urządzenia Bluetooth bez nazw"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokazuj opcje certyfikacji wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmniejsza zużycie baterii i zwiększa wydajność sieci"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kiedy ten tryb jest włączony, to adres MAC tego urządzenia może zmieniać się za każdym razem, kiedy urządzenie połączy się z siecią, która ma włączoną opcję randomizacji MAC"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kiedy ten tryb jest włączony, to adres MAC tego urządzenia może zmieniać się za każdym razem, kiedy urządzenie połączy się z siecią, która ma włączoną opcję randomizacji MAC"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Użycie danych jest mierzone"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Użycie danych nie jest mierzone"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Rozmiary bufora rejestratora"</string>
@@ -443,8 +443,8 @@
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Bateria może się wyczerpać do <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Wkrótce telefon może się wyłączyć"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Tablet może się wkrótce wyłączyć"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Urządzenie może się wkrótce wyłączyć"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4136ec2..6804c58 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 5abbc248..30dceaf0 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de display sem fios"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar o registo verboso de Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Controlo da procura de Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Seleção aleatória do MAC não persistente Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Seleção aleatória do MAC não persistente Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções da certificação de display sem fios"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo rápido da bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando este modo estiver ativado, o endereço MAC deste dispositivo pode mudar sempre que o mesmo estabelece ligação a uma rede que tenha a seleção aleatória do MAC ativada."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando este modo estiver ativado, o endereço MAC deste dispositivo pode mudar sempre que o mesmo estabelece ligação a uma rede que tenha a seleção aleatória do MAC ativada."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Acesso limitado"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Acesso ilimitado"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos da memória intermédia do registo"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4136ec2..6804c58 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 84064e6..0cd7926 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certificare Ecran wireless"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Înregistrare prin Wi-Fi de volume mari de date"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitare căutare de rețele Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Randomizarea adresei MAC nepersistente pentru Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizarea adresei MAC nepersistente pentru Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Date mobile permanent active"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accelerare hardware pentru tethering"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce descărcarea bateriei și îmbunătățește performanța rețelei"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Când acest mod este activat, adresa MAC a dispozitivului se poate schimba de fiecare dată când se conectează la o rețea care are activată randomizarea MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Când acest mod este activat, adresa MAC a dispozitivului se poate schimba de fiecare dată când se conectează la o rețea care are activată randomizarea MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Contorizată"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Necontorizată"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Dimensiunile memoriei temporare a jurnalului"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index ff799e0..418af9a 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Серт. беспроводн. мониторов"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Подробный журнал Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничивать поиск сетей Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Случайные MAC-адреса в сети Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Случайные MAC-адреса в сети Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Не отключать мобильный Интернет"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Аппаратное ускорение в режиме модема"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показывать параметры сертификации беспроводных мониторов"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Уменьшает расход заряда батареи и улучшает работу сети"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Если этот режим активирован, MAC-адрес устройства может меняться при каждом подключении к сети, в которой возможно создание случайных MAC-адресов."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Если этот режим активирован, MAC-адрес устройства может меняться при каждом подключении к сети, в которой возможно создание случайных MAC-адресов."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Сеть с тарификацией трафика"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Сеть без тарификации трафика"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Размер буфера журнала"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index ecd2888..ffe6472 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"නොරැහැන් සංදර්ශක සහතිකය"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"විස්තරාත්මක Wi‑Fi ලොග් කිරීම සබල කරන්න"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ස්කෑන් අවකරණය"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi අඛණ්ඩ නොවන MAC සසම්භාවීකරණය"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi අඛණ්ඩ නොවන MAC සසම්භාවීකරණය"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"ජංගම දත්ත සැමවිට ක්රියාකාරීය"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ටෙදරින් දෘඪාංග ත්වරණය"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"බැටරි බැසීම අඩු කරන අතර ජාල කාර්ය සාධනය වැඩි දියුණු කරයි"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"මෙම ප්රකාරය අබල කළ විට, මෙම උපාංගයේ MAC ලිපිනය එය MAC සසම්භාවීකරණය සබල කර ඇති ජාලයකට සම්බන්ධවන ඒ ඒ අවස්ථාවල වෙනස් විය හැකිය."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"මෙම ප්රකාරය සබල විට, මෙම උපාංගයේ MAC ලිපිනය එය MAC සසම්භාවීකරණය සබල කර ඇති ජාලයකට සම්බන්ධ වන එක් එක් අවස්ථාවල වෙනස් විය හැකිය."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"මනිනු ලැබේ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"මනින්නේ නැත"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ලෝගයේ අන්තරාවක ප්රමාණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5343543..7e46d1c 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikácia bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné denníky Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Pribrzdiť vyhľadávanie sietí Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Randomizácia dočasnej adresy MAC siete Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizácia dočasnej adresy MAC siete Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilné dáta ponechať vždy aktívne"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardvérová akcelerácia tetheringu"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Znižuje používanie batérie a zlepšuje výkon siete"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Keď je tento režim aktivovaný, adresa MAC tohto zariadenia sa môže pri každom pripojení k sieti s aktivovanou randomizáciou adries MAC zmeniť."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Keď je tento režim aktivovaný, adresa MAC tohto zariadenia sa môže pri každom pripojení k sieti s aktivovanou randomizáciou adries MAC zmeniť."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Merané"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez merania dát"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávacia pamäť nástroja denníkov"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 490d3aa..d498ac2 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -88,8 +88,8 @@
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Vnosna naprava"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Internetni dostop"</string>
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"Deljenje stikov"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Uporabi za dajanje stikov v skupno rabo"</string>
- <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Skupna raba internetne povezave"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Uporabi za deljenje stikov"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Deljenje internetne povezave"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Sporočila SMS"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostop do kartice SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
@@ -104,7 +104,7 @@
<string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Povezava s strežnikom za prenos datotek ni vzpostavljena"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Povezava z vnosno napravo je vzpostavljena"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Povezava z napravo za internetni dostop"</string>
- <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Skupna raba lok. internetne povezave z napravo"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Deljenje lok. internetne povezave z napravo"</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Uporabi za dostop do interneta"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Uporabi za zemljevid"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Uporablja se za dostop do kartice SIM"</string>
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogoči podrobno zapisovanje dnevnika za Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Omejevanje iskanja omrežij Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Dodeljevanje nestalnega naključnega naslova MAC za Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Dodeljevanje nestalnega naključnega naslova MAC za Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaži možnosti za potrdilo brezžičnega zaslona."</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije baterije in izboljša delovanje omrežja."</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ko je ta način omogočen, se lahko naslov MAC te naprave spremeni vsakič, ko se naprava poveže v omrežje z omogočenim naključnim dodeljevanjem naslova MAC."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ko je ta način omogočen, se lahko naslov MAC te naprave spremeni vsakič, ko se naprava poveže v omrežje z omogočenim dodeljevanjem naključnega naslova MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Omejen prenos podatkov"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Z neomejenim prenosom podatkov"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Velikosti medpomnilnikov zapisovalnika dnevnika"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 78b35aa..b004082 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -252,7 +252,8 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifikimi i ekranit pa tel"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivizo hyrjen Wi-Fi Verbose"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Përshpejtimi i skanimit të Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Renditje e rastësishme jo e përhershme e MAC për Wi‑Fi"</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
+ <skip />
<string name="mobile_data_always_on" msgid="8275958101875563572">"Të dhënat celulare gjithmonë aktive"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Përshpejtimi i harduerit për ndarjen e lidhjes (internet)"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string>
@@ -284,7 +285,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Shfaq opsionet për certifikimin e ekranit pa tel"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zvogëlon shkarkimin e baterisë dhe përmirëson cilësinë e funksionimit të rrjetit"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kur ky modalitet është i aktivizuar, adresa MAC e kësaj pajisjeje mund të ndryshojë çdo herë që lidhet me një rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC."</string>
+ <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"Me matje"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Pa matje"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Madhësitë e regjistruesit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 171ec75..5bb65e5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Сертификација бежичног екрана"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Омогући детаљнију евиденцију за Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Успоравање WiFi скенирања"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Насумично разврставање MAC адреса по WiFi-ју са прекидима"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Насумично разврставање MAC адреса по WiFi-ју са прекидима"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилни подаци су увек активни"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско убрзање привезивања"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Приказује опције за сертификацију бежичног екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Смањује потрошњу батерије и побољшава учинак мреже"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Када је овај режим омогућен, MAC адреса овог уређаја може да се промени сваки пут када се повеже са мрежом на којој је омогућено насумично разврставање MAC адреса."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Када је овај режим омогућен, MAC адреса овог уређаја може да се промени сваки пут када се повеже са мрежом на којој је омогућено насумично разврставање MAC адреса."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Са ограничењем"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничења"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Величине бафера података у програму за евидентирање"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 5517325..cee8d53 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certifiering för wifi-skärmdelning"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivera utförlig loggning för wifi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Begränsning av wifi-sökning"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Slumpgenerering av icke-beständig MAC för wifi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Slumpgenerering av icke-beständig MAC för wifi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata alltid aktiverad"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvaruacceleration för internetdelning"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Visa certifieringsalternativ för wifi-skärmdelning"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Öka loggningsnivån för wifi, visa per SSID RSSI i Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sänker batteriförbrukningen och förbättrar nätverksprestandan"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"När det här läget är aktiverat kan enhetens MAC-adress ändras varje gång den ansluts till ett nätverk där slumpgenerering av MAC-adress har aktiverats."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"När det här läget är aktiverat kan enhetens MAC-adress ändras varje gång den ansluts till ett nätverk där slumpgenerering av MAC-adress har aktiverats."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Med datapriser"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Utan datapriser"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Buffertstorlekar för logg"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index be4479f..4748118 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Washa Uwekaji kumbukumbu za WiFi kutumia Sauti"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Kudhibiti utafutaji wa Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Kuweka kwa unasibu anwani za MAC zisizo na muunganisho endelevu wa Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Kuweka kwa unasibu anwani za MAC zisizo na muunganisho endelevu wa Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Iendelee kutumia data ya simu"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Hupunguza matumizi ya chaji ya betri na kuboresha utendaji wa mtandao"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wakati hali hii imewashwa, huenda anwani ya MAC ya kifaa hiki ikabadilika kila wakati kinapounganisha kwenye mtandao ambapo kipengele cha unasibu wa MAC kimewashwa."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wakati hali hii imewashwa, huenda anwani ya MAC ya kifaa hiki ikabadilika kila wakati kinapounganisha kwenye mtandao ambapo kipengele cha unasibu wa MAC kimewashwa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mtandao unapima data"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mtandao usiopima data"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Ukubwa wa kiweka bafa ya kumbukumbu"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 6255d41..2f25722 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"வயர்லெஸ் காட்சிக்கான சான்றிதழ்"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"வைஃபை அதிவிவர நுழைவை இயக்கு"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"வைஃபை ஸ்கேனிங்கை வரம்பிடுதல்"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"வைஃபையில், மாறுபடும் MAC முகவரியைக் காண்பித்தல்"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"வைஃபையில் MAC முகவரியை ரேண்டம் ஆக்குதல்"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"மொபைல் டேட்டாவை எப்போதும் இயக்கத்திலேயே வை"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"இந்தப் பயன்முறை இயக்கப்படும்போது இந்தச் சாதனத்தின் MAC முகவரியானது ஒவ்வொரு முறை MAC ரேண்டம் ஆக்குதல் இயக்கப்பட்டிருக்கும் நெட்வொர்க்குடன் இணைக்கப்படும்போதும் மாறக்கூடும்."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"இந்தப் பயன்முறை இயக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தின் MAC முகவரி ஒவ்வொரு முறை \'MAC முகவரியை ரேண்டம் ஆக்குதல்\' இயக்கப்பட்டிருக்கும் நெட்வொர்க்குடன் இணைக்கப்படும்போதும் மாறக்கூடும்."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"கட்டண நெட்வொர்க்"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"கட்டணமில்லா நெட்வொர்க்"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"லாகர் பஃபர் அளவுகள்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a870026..71e4fe2 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"వైర్లెస్ డిస్ప్లే సర్టిఫికేషన్"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi విశదీకృత లాగింగ్ను ప్రారంభించండి"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi స్కాన్ కుదింపు"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi నిరంతరం కాని MAC ర్యాండమైజేషన్"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi నిరంతరం కాని MAC ర్యాండమైజేషన్"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"మొబైల్ డేటాని ఎల్లప్పుడూ యాక్టివ్గా ఉంచు"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"టెథెరింగ్ హార్డ్వేర్ వేగవృద్ధి"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు చూపించు"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్లెస్ డిస్ప్లే సర్టిఫికేషన్ ఆప్షన్లను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి & నెట్వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్ను ఎనేబుల్ చేసిన నెట్వర్క్తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్ మారవచ్చు."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్ను ఎనేబుల్ చేసిన నెట్వర్క్తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్ను మారవచ్చు."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"గణించబడుతోంది"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"గణించబడటం లేదు"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"లాగర్ బఫర్ సైజ్లు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 25fe87f..494a690 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"การรับรองการแสดงผลแบบไร้สาย"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"เปิดใช้การบันทึกรายละเอียด Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"การควบคุมการสแกนหา Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"การสุ่ม MAC ที่มี Wi-Fi ไม่ถาวร"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"การสุ่ม MAC ที่มี Wi-Fi ไม่ถาวร"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"เปิดใช้เน็ตมือถือเสมอ"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"แสดงตัวเลือกสำหรับการรับรองการแสดงผลแบบไร้สาย"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์นี้อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายที่มีการเปิดใช้การสุ่ม MAC"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายซึ่งเปิดใช้การสุ่ม MAC"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"แบบจำกัดปริมาณ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a219b5a..a6f93c5 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification ng wireless display"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"I-enable ang Pagla-log sa Wi‑Fi Verbose"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Pag-throttle ng pag-scan ng Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Pag-randomize sa MAC ng hindi persistent na Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Pag-randomize ng MAC na hindi persistent sa Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Palaging aktibo ang mobile data"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardware acceleration para sa pag-tether"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Binabawasan ang pagkaubos ng baterya at pinapahusay ang performance ng network"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kapag naka-enable ang mode na ito, puwedeng magbago ang MAC address ng device na ito sa tuwing kokonekta ito sa isang network na may naka-enable na MAC randomization."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kapag naka-enable ang mode na ito, puwedeng magbago ang MAC address ng device na ito sa tuwing kokonekta ito sa isang network na may naka-enable na pag-randomize ng MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Nakametro"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Hindi Nakametro"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mga laki ng buffer ng Logger"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index ad8cb8e..e1d9831 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Kablosuz ekran sertifikası"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Kablosuz Ayrıntılı Günlük Kaydını etkinleştir"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Kablosuz ağ taramasını kısma"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Kablosuz kalıcı olmayan MAC rastgele hale getirme süreci"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Kablosuz kalıcı olmayan MAC rastgele hale getirme süreci"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil veri her zaman etkin"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering donanım hızlandırıcısı"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Pili daha az harcar ve ağ performansını iyileştirir"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu mod etkinleştirildiğinde, bu cihaz MAC rastgele hale getirme işlevi açık olan bir ağa her bağlandığında cihazın MAC adresi değişebilir."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu mod etkinleştirildiğinde, bu cihaz MAC rastgele hale getirme işlevi açık olan bir ağa her bağlandığında cihazın MAC adresi değişebilir."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sayaçlı"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Sayaçsız"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Günlük Kaydedici arabellek boyutları"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 4d0d9b6..5b96e27 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Сертифікація бездрот. екрана"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Докладний запис у журнал Wi-Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Зменшити радіус пошуку мереж Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Випадкові MAC-адреси в мережі Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Випадкові MAC-адреси в мережі Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Не вимикати мобільне передавання даних"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратне прискорення під час використання телефона в режимі модема"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показати параметри сертифікації бездротового екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зменшує споживання заряду акумулятора й підвищує ефективність роботи мережі"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Якщо цей режим увімкнено, MAC-адреса пристрою може змінюватися щоразу, коли він підключається до мережі з довільним вибором MAC-адрес."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Коли цей режим увімкнено, MAC-адреса пристрою може змінюватися щоразу, коли він підключається до мережі з випадковими MAC-адресами."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"З тарифікацією трафіку"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без тарифікації трафіку"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Розміри буфера журналу"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index cf6013f..af60e9d 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"وائرلیس ڈسپلے سرٹیفیکیشن"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi وربوس لاگنگ فعال کریں"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi اسکین کو زبردستی روکا جا رہا ہے"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi-Fi غیر مستقل MAC کی رینڈمائزیشن"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi-Fi غیر مستقل MAC کی رینڈمائزیشن"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"ٹیدرنگ ہارڈویئر سرعت کاری"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"بیٹری ڈرین کم کرتا ہے اور نیٹ ورک کارکردگی کو بہتر بناتا ہے"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"جب یہ وضع فعال ہوتا ہے تو، اس آلہ کا MAC پتہ ہر بار تبدیل ہو سکتا ہے جب یہ کسی نیٹ ورک سے منسلک ہوتا ہے جس میں MAC ہے رینڈمائزیشن کو فعال کرتا ہے۔"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"اس وضع کے فعال ہونے پر اس آلے کا MAC پتہ ہر بار تبدیل ہو سکتا ہے جب بھی یہ کسی ایسے نیٹ ورک سے منسلک ہوتا ہے جس میں MAC رینڈمائزیشن فعال ہو۔"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"میٹرڈ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"غیر میٹر شدہ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"لاگر بفر کے سائز"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 34ef0d6..53f8520 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz monitor sertifikatlari"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Batafsil Wi-Fi jurnali"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi tarmoqni taqsimlab skanlash"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi MAC manzilini muddatli tasodiflash"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi MAC manzilini muddatli tasodiflash"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil internet doim yoniq tursin"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Modem rejimida apparatli tezlashtirish"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya sarfini tejaydi va tarmoq samaradorligini oshiradi"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyati mavjud tarmoqqa har safar ulanganda almashishi mumkin."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyati mavjud tarmoqqa har safar ulanganda almashishi mumkin."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Trafik hisoblanadigan tarmoq"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Trafik hisobi yuritilmaydigan tarmoq"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi hajmi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index a67ea6a..bf4ab28 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Bật ghi nhật ký chi tiết Wi‑Fi"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Hạn chế quét tìm Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Sắp xếp ngẫu nhiên địa chỉ MAC không ổn định khi kết nối Wi-Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Tạo địa chỉ MAC ngẫu nhiên, không cố định mỗi khi kết nối Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Dữ liệu di động luôn hoạt động"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Tăng tốc phần cứng khi chia sẻ Internet"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiện các thiết bị Bluetooth không có tên"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Giảm hao pin và cải thiện hiệu suất mạng"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Khi bật chế độ này, địa chỉ MAC của thiết bị này có thể thay đổi mỗi lần thiết bị kết nối với mạng đã bật tính năng sử dụng địa chỉ MAC ngẫu nhiên."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Khi bật chế độ này, địa chỉ MAC của thiết bị này có thể thay đổi mỗi lần thiết bị kết nối với mạng đã bật chế độ tạo địa chỉ MAC ngẫu nhiên."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Đo lượng dữ liệu"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Không đo lượng dữ liệu"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Kích thước bộ đệm của trình ghi nhật ký"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index e991451..aac8eed 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"无线显示认证"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"启用 WLAN 详细日志记录功能"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"WLAN 扫描调节"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"为 WLAN 热点随机生成非持久性 MAC 地址"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"为 WLAN 热点随机生成非持久性 MAC 地址"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"始终开启移动数据网络"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"网络共享硬件加速"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"提升 WLAN 日志记录级别(在 WLAN 选择器中显示每个 SSID 的 RSSI)"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗电量以及改善网络性能"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"启用此模式后,每当此设备连接到已启用随机分配 MAC 地址功能的网络时,它的 MAC 地址就可能会发生更改。"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"启用此模式后,这台设备每次连接到已启用随机生成 MAC 地址功能的网络时,其 MAC 地址都可能会更改。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按流量计费"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不按流量计费"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"日志记录器缓冲区大小"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 6d8a0b0..78b57cc 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 掃瞄限流"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"一律保持啟用流動數據"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"網絡共享硬件加速"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"減低耗電量並改善網絡表現"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用此模式後,每次連接至已啟用 MAC 隨機處理的網絡時,此裝置的 MAC 位址都可能會變更。"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"啟用此模式後,每次連接至已啟用 MAC 隨機處理的網絡時,此裝置的 MAC 位址都可能會變更。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按用量收費"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不限數據用量收費"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 53be010..637714a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄設定"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi 掃描調節"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"行動數據連線一律保持啟用狀態"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"網路共用硬體加速"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細記錄"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗電量以及改善網路效能"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用這個模式後,每次連線到啟用了 MAC 隨機化的網路時,這部裝置的 MAC 位址都可能會有所變更。"</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"這個模式啟用後,每當這部裝置連線到已啟用隨機 MAC 位址的網路時,裝置的 MAC 位址可能都會改變。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"計量付費"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"非計量付費"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 9daa41c..ae262fc 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -252,7 +252,7 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Ukunikezwa isitifiketi sokubukeka okungenantambo"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Nika amandlaukungena kwe-Wi-Fi Verbose"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"I-throttling yokuskena kwe-Wi-Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="882650208573834301">"Okungahleliwe kwe-MAC engaphikeleli ye-Wi‑Fi"</string>
+ <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Okungahleliwe kwe-MAC engaphikeleli ye-Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Idatha yeselula ihlala isebenza"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"I-Tethering hardware acceleration"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Yehlisa ukuphela kwebhethri futhi ithuthukise ukusebenza kwenethiwekhi"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Uma le modi inikwe amandla, ikheli le-MAC lale divayisi lingashintsha njalo uma ixhuma kunethiwekhi ene-MAC engahleliwe enikwe amandla."</string>
+ <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Uma le modi inikwe amandla, ikheli le-MAC lale divayisi lingashintsha njalo uma ixhuma kunethiwekhi ene-MAC engahleliwe enikwe amandla."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kulinganisiwe"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Akulinganiselwa"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Amasayizi weloga ngebhafa"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6b840bd..183a06c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -20,67 +20,67 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Toast message when Wi-Fi cannot scan for networks -->
<string name="wifi_fail_to_scan">Can\'t scan for networks</string>
- <!-- Do not translate. Concise terminology for wifi with WEP security -->
+ <!-- Concise terminology for wifi with WEP security -->
<string name="wifi_security_short_wep" translatable="false">WEP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA security -->
+ <!-- Concise terminology for wifi with WPA security -->
<string name="wifi_security_short_wpa" translatable="false">WPA</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2 security -->
+ <!-- Concise terminology for wifi with WPA2 security -->
<string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
- <!-- Do not translate. Concise terminology for wifi with both WPA/WPA2 security -->
+ <!-- Concise terminology for wifi with both WPA/WPA2 security -->
<string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
- <!-- Do not translate. Concise terminology for wifi with unknown PSK type -->
+ <!-- Concise terminology for wifi with unknown PSK type -->
<string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_short_eap" translatable="false">802.1x</string>
- <!-- Do not translate. Concise terminology for wifi with WPA 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
<string name="wifi_security_short_eap_wpa" translatable="false">WPA-EAP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_short_eap_wpa2_wpa3" translatable="false">RSN-EAP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA3 security -->
+ <!-- Concise terminology for wifi with WPA3 security -->
<string name="wifi_security_short_sae" translatable="false">WPA3</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 transition security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 transition security -->
<string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
- <!-- Do not translate. Concise terminology for Wi-Fi with None/OWE transition mode security -->
+ <!-- Concise terminology for Wi-Fi with None/OWE transition mode security -->
<string name="wifi_security_short_none_owe" translatable="false">None/OWE</string>
- <!-- Do not translate. Concise terminology for wifi with OWE security -->
+ <!-- Concise terminology for wifi with OWE security -->
<string name="wifi_security_short_owe" translatable="false">OWE</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
<string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B-192</string>
<!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. [CHAR LIMIT=40] -->
<string name="wifi_security_none">None</string>
- <!-- Do not translate. Terminology for wifi with WEP security -->
+ <!-- Terminology for wifi with WEP security -->
<string name="wifi_security_wep" translatable="false">WEP</string>
- <!-- Do not translate. Terminology for wifi with WPA security -->
+ <!-- Terminology for wifi with WPA security -->
<string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
- <!-- Do not translate. Terminology for wifi with WPA2 security -->
+ <!-- Terminology for wifi with WPA2 security -->
<string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
- <!-- Do not translate. Terminology for wifi with both WPA/WPA2 security, or unknown -->
+ <!-- Terminology for wifi with both WPA/WPA2 security, or unknown -->
<string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
- <!-- Do not translate. Terminology for wifi with unknown PSK type -->
+ <!-- Terminology for wifi with unknown PSK type -->
<string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_eap" translatable="false">WPA/WPA2/WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
<string name="wifi_security_eap_wpa" translatable="false">WPA-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_eap_wpa_wpa2" translatable="false">WPA/WPA2-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA3 802.1x EAP security -->
<string name="wifi_security_eap_wpa3" translatable="false">WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for Passpoint network -->
+ <!-- Concise terminology for Passpoint network -->
<string name="wifi_security_passpoint" translatable="false">Passpoint</string>
- <!-- Do not translate. Terminology for wifi with WPA3 security -->
+ <!-- Terminology for wifi with WPA3 security -->
<string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
- <!-- Do not translate. Terminology for wifi with WPA2/WPA3 Transition mode security -->
+ <!-- Terminology for wifi with WPA2/WPA3 Transition mode security -->
<string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
- <!-- Do not translate. Terminology for Wi-Fi with None/OWE transition mode security -->
+ <!-- Terminology for Wi-Fi with None/OWE transition mode security -->
<string name="wifi_security_none_owe" translatable="false">None/Enhanced Open</string>
- <!-- Do not translate. Terminology for wifi with OWE security -->
+ <!-- Terminology for wifi with OWE security -->
<string name="wifi_security_owe" translatable="false">Enhanced Open</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
<string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise 192-bit</string>
<!-- Summary for the remembered network. -->
@@ -654,7 +654,7 @@
<!-- Setting Checkbox title whether to disable WiFi Scan Throttling. [CHAR LIMIT=40] -->
<string name="wifi_scan_throttling">Wi\u2011Fi scan throttling</string>
<!-- Setting Checkbox title whether to enable WiFi non-persistent mac randomization. [CHAR LIMIT=80] -->
- <string name="wifi_enhanced_mac_randomization">Wi\u2011Fi non\u2011persistent MAC randomization</string>
+ <string name="wifi_non_persistent_mac_randomization">Wi\u2011Fi non\u2011persistent MAC randomization</string>
<!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Mobile data always active</string>
<!-- Setting Checkbox title whether to enable hardware acceleration for tethering. [CHAR LIMIT=80] -->
@@ -722,8 +722,8 @@
<string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string>
<!-- Setting Checkbox summary whether to disable Wifi scan throttling [CHAR LIMIT=NONE] -->
<string name="wifi_scan_throttling_summary">Reduces battery drain & improves network performance</string>
- <!-- Setting Checkbox title whether to enable WiFi enhanced mac randomization. [CHAR LIMIT=NONE] -->
- <string name="wifi_enhanced_mac_randomization_summary">When this mode is enabled, this device\u2019s MAC address may change each time it connects to a network that has MAC randomization enabled.</string>
+ <!-- Setting Checkbox summary whether to enable WiFi non-persistent mac randomization. [CHAR LIMIT=NONE] -->
+ <string name="wifi_non_persistent_mac_randomization_summary">When this mode is enabled, this device\u2019s MAC address may change each time it connects to a network that has MAC randomization enabled.</string>
<!-- Label indicating network has been manually marked as metered -->
<string name="wifi_metered_label">Metered</string>
<!-- Label indicating network has been manually marked as unmetered -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
index bd9e0d3..7275d6b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
@@ -18,6 +18,9 @@
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;
@@ -43,7 +46,11 @@
} else if (isFinancedDevice(context)) {
return new FinancedDeviceActionDisabledByAdminController(stringProvider);
} else {
- return new ManagedDeviceActionDisabledByAdminController(stringProvider, userHandle);
+ return new ManagedDeviceActionDisabledByAdminController(
+ stringProvider,
+ userHandle,
+ DEFAULT_FOREGROUND_USER_CHECKER,
+ DEFAULT_RESOLVE_ACTIVITY_CHECKER);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
index 4114879..f9d3aaf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
@@ -22,6 +22,7 @@
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;
@@ -34,6 +35,17 @@
*/
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
*/
@@ -111,6 +123,14 @@
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 93e811d..c2034f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
@@ -20,13 +20,14 @@
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 java.util.Objects;
+import com.android.settingslib.enterprise.ActionDisabledLearnMoreButtonLauncher.ResolveActivityChecker;
/**
@@ -35,17 +36,37 @@
final class ManagedDeviceActionDisabledByAdminController
extends BaseActionDisabledByAdminController {
- private final UserHandle mUserHandle;
+ 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;
/**
* Constructs a {@link ManagedDeviceActionDisabledByAdminController}
- * @param userHandle - user on which to launch the help web page, if necessary
+ * @param preferredUserHandle - user on which to launch the help web page, if necessary
*/
ManagedDeviceActionDisabledByAdminController(
DeviceAdminStringProvider stringProvider,
- UserHandle userHandle) {
+ UserHandle preferredUserHandle,
+ ForegroundUserChecker foregroundUserChecker,
+ ResolveActivityChecker resolveActivityChecker) {
super(stringProvider);
- mUserHandle = requireNonNull(userHandle);
+ mPreferredUserHandle = requireNonNull(preferredUserHandle);
+ mForegroundUserChecker = requireNonNull(foregroundUserChecker);
+ mResolveActivityChecker = requireNonNull(resolveActivityChecker);
}
@Override
@@ -53,14 +74,52 @@
assertInitialized();
String url = mStringProvider.getLearnMoreHelpPageUrl();
- if (TextUtils.isEmpty(url)) {
+
+ if (!TextUtils.isEmpty(url)
+ && canLaunchHelpPageInPreferredOrCurrentUser(context, url, mPreferredUserHandle)) {
+ setupLearnMoreButtonToLaunchHelpPage(context, url, mPreferredUserHandle);
+ } else {
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 d9be4f3..509e12d 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,6 +30,8 @@
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;
@@ -45,9 +47,11 @@
@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();
@@ -60,8 +64,21 @@
}
@Test
- public void setupLearnMoreButton_validUrl_negativeButtonSet() {
- ManagedDeviceActionDisabledByAdminController controller = createController(URL);
+ public void setupLearnMoreButton_noUrl_negativeButtonSet() {
+ ManagedDeviceActionDisabledByAdminController controller = createController(EMPTY_URL);
+
+ controller.setupLearnMoreButton(mContext);
+
+ mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES);
+ }
+
+ @Test
+ public void setupLearnMoreButton_validUrl_foregroundUser_launchesHelpPage() {
+ ManagedDeviceActionDisabledByAdminController controller = createController(
+ URL,
+ /* isUserForeground= */ true,
+ /* preferredUserHandle= */ MANAGED_USER,
+ /* userContainingBrowser= */ MANAGED_USER);
controller.setupLearnMoreButton(mContext);
@@ -69,8 +86,38 @@
}
@Test
- public void setupLearnMoreButton_noUrl_negativeButtonSet() {
- ManagedDeviceActionDisabledByAdminController controller = createController(EMPTY_URL);
+ 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);
@@ -110,13 +157,33 @@
}
private ManagedDeviceActionDisabledByAdminController createController() {
- return createController(/* url= */ null);
+ return createController(
+ /* url= */ null,
+ /* foregroundUserChecker= */ true,
+ mContext.getUser(),
+ /* userContainingBrowser= */ 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), mContext.getUser());
+ new FakeDeviceAdminStringProvider(url),
+ preferredUserHandle,
+ /* foregroundUserChecker= */ (context, userHandle) -> isUserForeground,
+ /* resolveActivityChecker= */ (packageManager, __, userHandle) ->
+ userHandle.equals(userContainingBrowser));
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/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 58ca734..0d03f33 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -27,7 +27,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -108,7 +107,7 @@
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
- mShadowRouter2Manager.setAvailableRoutes(routes);
+ mShadowRouter2Manager.setTransferableRoutes(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
@@ -159,7 +158,7 @@
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
- mShadowRouter2Manager.setAvailableRoutes(routes);
+ mShadowRouter2Manager.setTransferableRoutes(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
@@ -195,7 +194,7 @@
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
- mShadowRouter2Manager.setAvailableRoutes(routes);
+ mShadowRouter2Manager.setTransferableRoutes(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
@@ -618,7 +617,7 @@
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
- mShadowRouter2Manager.setAvailableRoutes(routes);
+ mShadowRouter2Manager.setTransferableRoutes(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
@@ -728,9 +727,8 @@
final MediaRoute2Info info = mock(MediaRoute2Info.class);
final List<MediaRoute2Info> infos = new ArrayList<>();
infos.add(info);
- mShadowRouter2Manager.setAvailableRoutes(infos);
+ mShadowRouter2Manager.setTransferableRoutes(infos);
- when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
when(info.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
assertThat(mInfoMediaManager.shouldDisableMediaOutput("test")).isTrue();
@@ -741,9 +739,8 @@
final MediaRoute2Info info = mock(MediaRoute2Info.class);
final List<MediaRoute2Info> infos = new ArrayList<>();
infos.add(info);
- mShadowRouter2Manager.setAvailableRoutes(infos);
+ mShadowRouter2Manager.setTransferableRoutes(infos);
- when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
when(info.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
assertThat(mInfoMediaManager.shouldDisableMediaOutput("test")).isFalse();
@@ -757,9 +754,8 @@
final List<MediaRoute2Info> infos = new ArrayList<>();
infos.add(info);
infos.add(info2);
- mShadowRouter2Manager.setAvailableRoutes(infos);
+ mShadowRouter2Manager.setTransferableRoutes(infos);
- when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
when(info.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
when(info2.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
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/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
new file mode 100644
index 0000000..34efe82
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SelectorWithWidgetPreferenceTest {
+
+ private Application mContext;
+ private SelectorWithWidgetPreference mPreference;
+
+ private View mExtraWidgetContainer;
+ private View mExtraWidget;
+
+ private boolean mIsClickListenerCalled;
+ private View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mIsClickListenerCalled = true;
+ }
+ };
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mPreference = new SelectorWithWidgetPreference(mContext);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_selector_with_widget, null /* root */);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+ mPreference.onBindViewHolder(preferenceViewHolder);
+
+ mExtraWidgetContainer = view.findViewById(R.id.selector_extra_widget_container);
+ mExtraWidget = view.findViewById(R.id.selector_extra_widget);
+ }
+
+ @Test
+ public void shouldHaveRadioPreferenceLayout() {
+ assertThat(mPreference.getLayoutResource()).isEqualTo(
+ R.layout.preference_selector_with_widget);
+ }
+
+ @Test
+ public void shouldHaveRadioButtonWidgetLayoutByDefault() {
+ assertThat(mPreference.getWidgetLayoutResource())
+ .isEqualTo(R.layout.preference_widget_radiobutton);
+ }
+
+ @Test
+ public void shouldHaveCheckBoxWidgetLayoutIfSet() {
+ mPreference = new SelectorWithWidgetPreference(mContext, true);
+ assertThat(mPreference.getWidgetLayoutResource())
+ .isEqualTo(R.layout.preference_widget_checkbox);
+ }
+
+ @Test
+ public void iconSpaceReservedShouldBeFalse() {
+ assertThat(mPreference.isIconSpaceReserved()).isFalse();
+ }
+
+ @Test
+ public void onBindViewHolder_withSummary_containerShouldBeVisible() {
+ mPreference.setSummary("some summary");
+ View summaryContainer = new View(mContext);
+ View view = mock(View.class);
+ when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+
+ mPreference.onBindViewHolder(preferenceViewHolder);
+
+ assertEquals(View.VISIBLE, summaryContainer.getVisibility());
+ }
+
+ @Test
+ public void onBindViewHolder_emptySummary_containerShouldBeGone() {
+ mPreference.setSummary("");
+ View summaryContainer = new View(mContext);
+ View view = mock(View.class);
+ when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+
+ mPreference.onBindViewHolder(preferenceViewHolder);
+
+ assertEquals(View.GONE, summaryContainer.getVisibility());
+ }
+
+ @Test
+ public void nullSummary_containerShouldBeGone() {
+ mPreference.setSummary(null);
+ View summaryContainer = new View(mContext);
+ View view = mock(View.class);
+ when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+ mPreference.onBindViewHolder(preferenceViewHolder);
+ assertEquals(View.GONE, summaryContainer.getVisibility());
+ }
+
+ @Test
+ public void setAppendixVisibility_setGone_shouldBeGone() {
+ mPreference.setAppendixVisibility(View.GONE);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_selector_with_widget, null /* root */);
+ PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
+ mPreference.onBindViewHolder(holder);
+ assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void setExtraWidgetListener_setNull_extraWidgetShouldInvisible() {
+ mPreference.setExtraWidgetOnClickListener(null);
+
+ assertEquals(View.GONE, mExtraWidgetContainer.getVisibility());
+ }
+
+ @Test
+ public void setExtraWidgetListener_extraWidgetShouldVisible() {
+ mPreference.setExtraWidgetOnClickListener(mClickListener);
+
+ assertEquals(View.VISIBLE, mExtraWidgetContainer.getVisibility());
+ }
+
+ @Test
+ public void onClickListener_setExtraWidgetOnClickListener_ShouldCalled() {
+ mPreference.setExtraWidgetOnClickListener(mClickListener);
+
+ assertThat(mIsClickListenerCalled).isFalse();
+ mExtraWidget.callOnClick();
+ assertThat(mIsClickListenerCalled).isTrue();
+ }
+}
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/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
index 5bb5500..5959863 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
@@ -85,4 +85,13 @@
return (ShadowRouter2Manager) Shadow.extract(
MediaRouter2Manager.getInstance(RuntimeEnvironment.application));
}
+
+ @Implementation
+ protected List<MediaRoute2Info> getTransferableRoutes(String packageName) {
+ return mAvailableRoutes;
+ }
+
+ public void setTransferableRoutes(List<MediaRoute2Info> infos) {
+ mAvailableRoutes = infos;
+ }
}
diff --git a/packages/SettingsProvider/res/values-gu/strings.xml b/packages/SettingsProvider/res/values-gu/strings.xml
index 1f91f71..dded10e 100644
--- a/packages/SettingsProvider/res/values-gu/strings.xml
+++ b/packages/SettingsProvider/res/values-gu/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"સેટિંગ્સ સંગ્રહ"</string>
+ <string name="app_label" msgid="4567566098528588863">"સેટિંગ સ્ટોરેજ"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"હૉટસ્પૉટ સેટિંગ બદલાઈ ગઈ છે"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"વિગતો જોવા માટે ટૅપ કરો"</string>
</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index b84a9cd..0ad8f39d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -79,5 +79,7 @@
Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
Settings.Global.POWER_BUTTON_LONG_PRESS,
+ Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+ Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 690ace7..9bc8e65 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -20,6 +20,7 @@
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR;
import static android.view.Display.HdrCapabilities.HDR_TYPES;
@@ -116,6 +117,7 @@
VALIDATORS.put(Global.CLOCKWORK_SYSUI_MAIN_ACTIVITY_NAME, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.CLOCKWORK_SYSUI_PACKAGE_NAME, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.CLOCKWORK_HOME_READY, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Global.ENABLE_TARE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.PRIVATE_DNS_MODE, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.PRIVATE_DNS_SPECIFIER, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.SOFT_AP_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
@@ -143,6 +145,8 @@
/* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.AUTOMATIC_POWER_SAVE_MODE, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(Global.ADVANCED_BATTERY_USAGE_AMOUNT, PERCENTAGE_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.HAS_PAY_TOKENS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, ANY_INTEGER_VALIDATOR);
@@ -157,12 +161,12 @@
String.valueOf(Global.Wearable.RETAIL_MODE_RETAIL)
}));
VALIDATORS.put(
- Global.Wearable.PLAY_STORE_AVAILABILITY,
+ Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
new DiscreteValueValidator(
new String[] {
- String.valueOf(Global.Wearable.PLAY_STORE_AVAILABLE),
- String.valueOf(Global.Wearable.PLAY_STORE_UNAVAILABLE),
- String.valueOf(Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN)
+ String.valueOf(Global.Wearable.PHONE_PLAY_STORE_AVAILABLE),
+ String.valueOf(Global.Wearable.PHONE_PLAY_STORE_UNAVAILABLE),
+ String.valueOf(Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN)
}));
VALIDATORS.put(
Global.Wearable.BUG_REPORT,
@@ -291,6 +295,24 @@
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);
+ VALIDATORS.put(Global.Wearable.MASTER_GESTURES_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.UNGAZE_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(
+ Global.Wearable.BATTERY_SAVER_MODE,
+ new DiscreteValueValidator(
+ new String[] {
+ String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_NONE),
+ String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_LIGHT),
+ String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_TRADITIONAL_WATCH),
+ String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_TIME_ONLY),
+ String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_CUSTOM)
+ }));
+ VALIDATORS.put(
+ Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+ NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_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..bf8b933 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -34,7 +34,9 @@
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
import android.provider.Settings.Secure;
+import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import java.util.Map;
@@ -69,6 +71,7 @@
Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
COLON_SEPARATED_COMPONENT_LIST_VALIDATOR);
VALIDATORS.put(Secure.TOUCH_EXPLORATION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.WEAR_TALKBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(
Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
@@ -276,7 +279,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,
@@ -287,5 +290,32 @@
VALIDATORS.put(Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DEVICE_STATE_ROTATION_LOCK, value -> {
+ if (TextUtils.isEmpty(value)) {
+ return true;
+ }
+ String[] intValues = value.split(":");
+ if (intValues.length % 2 != 0) {
+ return false;
+ }
+ InclusiveIntegerRangeValidator enumValidator =
+ new InclusiveIntegerRangeValidator(
+ Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED,
+ Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ ArraySet<String> keys = new ArraySet<>();
+ for (int i = 0; i < intValues.length - 1; ) {
+ String entryKey = intValues[i++];
+ String entryValue = intValues[i++];
+ if (!NON_NEGATIVE_INTEGER_VALIDATOR.validate(entryKey)
+ || !enumValidator.validate(entryValue)) {
+ return false;
+ }
+ // If the same device state key was specified more than once, this is invalid
+ if (!keys.add(entryKey)) {
+ return false;
+ }
+ }
+ return true;
+ });
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9e7daf4..294399e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5215,8 +5215,8 @@
initGlobalSettingsDefaultValForWearLocked(
Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
initGlobalSettingsDefaultValForWearLocked(
- Global.Wearable.PLAY_STORE_AVAILABILITY,
- Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN);
+ Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
+ Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN);
initGlobalSettingsDefaultValForWearLocked(
Global.Wearable.BUG_REPORT,
"user".equals(Build.TYPE) // is user build?
@@ -5380,6 +5380,20 @@
initGlobalSettingsDefaultValForWearLocked(
Settings.Global.Wearable.COMPANION_OS_VERSION,
Settings.Global.Wearable.COMPANION_OS_VERSION_UNDEFINED);
+ final boolean defaultBurnInProtectionEnabled =
+ getContext()
+ .getResources()
+ .getBoolean(
+ com.android
+ .internal
+ .R
+ .bool
+ .config_enableBurnInProtection);
+ final boolean forceBurnInProtection =
+ SystemProperties.getBoolean("persist.debug.force_burn_in", false);
+ initGlobalSettingsDefaultValForWearLocked(
+ Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
+ defaultBurnInProtectionEnabled || forceBurnInProtection);
// TODO(b/164398026): add necessary initialization logic for all entries.
currentVersion = 204;
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9e65799..ec2ec66 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 =
@@ -137,7 +138,6 @@
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
- Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
@@ -265,6 +265,7 @@
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
Settings.Global.ENABLE_RESTRICTED_BUCKET,
+ Settings.Global.ENABLE_TARE,
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
@@ -592,7 +593,8 @@
Settings.Global.CACHED_APPS_FREEZER_ENABLED,
Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
- Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
+ Settings.Global.Wearable.BATTERY_SAVER_MODE,
+ Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
Settings.Global.Wearable.HAS_PAY_TOKENS,
Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
Settings.Global.Wearable.HOTWORD_DETECTION_ENABLED,
@@ -600,7 +602,7 @@
Settings.Global.Wearable.DEFAULT_VIBRATION,
Settings.Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
Settings.Global.Wearable.RETAIL_MODE,
- Settings.Global.Wearable.PLAY_STORE_AVAILABILITY,
+ Settings.Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
Settings.Global.Wearable.BUG_REPORT,
Settings.Global.Wearable.SMART_ILLUMINATE_ENABLED,
Settings.Global.Wearable.CLOCKWORK_AUTO_TIME,
@@ -654,7 +656,12 @@
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,
+ Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
+ Settings.Global.Wearable.UNGAZE_ENABLED,
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+ Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED);
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/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 1fc27ca..76702d6 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -24,7 +24,7 @@
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Poročilo o napakah bo kmalu prikazano v telefonu"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Izberite za pošiljanje poročila o napakah"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite poročilo o napaki dati v skupno rabo"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite deliti poročilo o napaki"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Izberite za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</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/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index bd2209b..0424382 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -52,13 +52,6 @@
void setListening(boolean listening);
boolean isShowingDetail();
void closeDetail();
-
- /**
- * Set that we're currently pulse expanding
- *
- * @param pulseExpanding if we're currently expanding during pulsing
- */
- default void setPulseExpanding(boolean pulseExpanding) {}
void animateHeaderSlidingOut();
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
void setHeaderListening(boolean listening);
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-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index c3e8e61..21f32cf 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 1abd393..009b7cb 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -74,7 +74,7 @@
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Confirm desired PIN code"</string>
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-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 0b1efa8..fb2571e 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -61,7 +61,7 @@
<string name="error_disable_esim_msg" msgid="2441188596467999327">"Det gick inte att inaktivera eSIM-kortet på grund av ett fel."</string>
<string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Retur"</string>
<string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"Har du glömt ditt grafiska lösenord?"</string>
- <string name="kg_wrong_pattern" msgid="5907301342430102842">"Fel grafiskt lösenord"</string>
+ <string name="kg_wrong_pattern" msgid="5907301342430102842">"Fel mönster"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Fel lösenord"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"Fel pinkod"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914">
@@ -82,7 +82,7 @@
<string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ange en pinkod med fyra till åtta siffror."</string>
<string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden ska vara minst åtta siffror."</string>
<string name="kg_invalid_puk" msgid="1774337070084931186">"Ange rätt PUK-kod. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
- <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med grafiskt lösenord"</string>
+ <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med mönster"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har angett fel pinkod <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
@@ -102,13 +102,13 @@
<string name="keyguard_carrier_default" msgid="6359808469637388586">"Ingen tjänst."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Byt inmatningsmetod"</string>
<string name="airplane_mode" msgid="2528005343938497866">"Flygplansläge"</string>
- <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste ange grafiskt lösenord när du har startat om enheten"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste rita mönster när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du måste ange pinkod när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du måste ange lösenord när du har startat om enheten"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du måste ange grafiskt lösenord för ytterligare säkerhet"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du måste rita mönster för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Du måste ange pinkod för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du måste ange lösenord för ytterligare säkerhet"</string>
- <string name="kg_prompt_reason_switch_profiles_pattern" msgid="1922016914701991230">"Du måste ange grafiskt lösenord när du byter profil"</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="1922016914701991230">"Du måste rita mönster när du byter profil"</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="6490434826361055400">"Du måste ange pinkod när du byter profil"</string>
<string name="kg_prompt_reason_switch_profiles_password" msgid="1680374696393804441">"Du måste ange lösenord när du byter profil"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
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/anim/progress_indeterminate_horizontal_rect.xml b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
new file mode 100644
index 0000000..13133cb
--- /dev/null
+++ b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_rect2 in frameworks/base/core/res -->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="2000"
+ android:propertyXName="translateX"
+ android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0 "
+ android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_translatex_copy"
+ android:repeatCount="infinite" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-nodpi/android_12.xml b/packages/SystemUI/res/drawable-nodpi/android_12.xml
new file mode 100644
index 0000000..bdeeced
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_12.xml
@@ -0,0 +1,37 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <group>
+ <clip-path
+ android:pathData="M14,14h21v20h-21z"/>
+ <path
+ android:pathData="M15,15C15.7956,15 16.5587,15.3161 17.1213,15.8787C17.6839,16.4413 18,17.2044 18,18V33"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M34,33H22V30C22,28.4087 22.6321,26.8826 23.7574,25.7574C24.8826,24.6321 26.4087,24 28,24H31C31.7956,24 32.5587,23.6839 33.1213,23.1213C33.6839,22.5587 34,21.7957 34,21C34.009,19.5779 33.5126,18.1989 32.5993,17.1088C31.686,16.0188 30.4153,15.2885 29.0136,15.0483C27.612,14.8081 26.1706,15.0735 24.9464,15.7973C23.7223,16.5211 22.795,17.6561 22.33,19C22.2199,19.3261 22.1363,19.6605 22.08,20"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 7f8d4fa..9972496 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_12"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index 31b2a7f..ff7cbae 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent1_500" />
diff --git a/packages/SystemUI/res/drawable/controls_icon.xml b/packages/SystemUI/res/drawable/controls_icon.xml
new file mode 100644
index 0000000..f1814a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_icon.xml
@@ -0,0 +1,25 @@
+<?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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,3L4,9v12h16L20,9l-8,-6zM18,19h-3v-6L9,13v6L6,19v-9l6,-4.5 6,4.5v9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/fingerprint_bg.xml b/packages/SystemUI/res/drawable/fingerprint_bg.xml
index 2b0ab6f..558ec08 100644
--- a/packages/SystemUI/res/drawable/fingerprint_bg.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_bg.xml
@@ -14,10 +14,11 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="oval">
<solid
- android:color="?android:attr/colorBackground"/>
+ android:color="?androidprv:attr/colorSurface"/>
<size
android:width="64dp"
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
new file mode 100644
index 0000000..c3b3469
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_unlock.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:translateX="8.625" android:translateY="13.625">
+ <path
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData="M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+ </group>
+ <group android:translateX="14" android:translateY="13.5">
+ <path
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
+ </group>
+ <group android:translateX="20" android:translateY="35.75">
+ <path
+ android:fillColor="#FF000000"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml
rename to packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
diff --git a/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 0000000..95209f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_material_trimmed in frameworks/base/core/res -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+ <target
+ android:name="rect_grp"
+ android:animation="@anim/progress_indeterminate_horizontal_rect" />
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 0000000..aec204f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:height="10dp"
+ android:width="340dp"
+ android:viewportHeight="10"
+ android:viewportWidth="340" >
+ <group
+ android:name="progress_group"
+ android:translateX="180"
+ android:translateY="5" >
+ <path
+ android:name="background_track"
+ android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+ android:fillColor="?androidprv:attr/colorSurfaceVariant"/>
+ <group
+ android:name="rect_grp"
+ android:translateX="-197.60001"
+ android:scaleX="0.5" >
+ <path
+ android:name="rect"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?androidprv:attr/colorAccentPrimaryVariant" />
+ </group>
+ </group>
+</vector>
\ No newline at end of file
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..4406a46
--- /dev/null
+++ b/packages/SystemUI/res/layout/communal_host_view.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- 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"
+ systemui:layout_constraintStart_toStartOf="parent"
+ systemui:layout_constraintTop_toTopOf="parent"
+ systemui:layout_constraintBottom_toBottomOf="parent"
+ systemui:layout_constraintHeight_percent="@dimen/communal_source_height_percentage"
+ android:layout_width="0dp"
+ android:layout_height="0dp"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/idle_host_view.xml b/packages/SystemUI/res/layout/idle_host_view.xml
new file mode 100644
index 0000000..f407874
--- /dev/null
+++ b/packages/SystemUI/res/layout/idle_host_view.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+
+<com.android.systemui.idle.IdleHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/idle_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 7f22b71..f7919d4 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -17,6 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/internet_connectivity_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -28,7 +29,7 @@
style="@style/Widget.SliceView.Panel"
android:gravity="center_vertical|center_horizontal"
android:layout_marginTop="24dp"
- android:layout_marginBottom="24dp"
+ android:layout_marginBottom="16dp"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -46,7 +47,7 @@
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
android:layout_height="20dp"
- android:layout_marginTop="8dp"
+ android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="google-sans"
@@ -54,18 +55,20 @@
</LinearLayout>
<View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"/>
+ android:id="@+id/divider"
+ android:layout_gravity="center_vertical|center_horizontal"
+ android:layout_width="340dp"
+ android:layout_height="4dp"
+ android:background="?androidprv:attr/colorSurfaceVariant"/>
<ProgressBar
android:id="@+id/wifi_searching_progress"
android:indeterminate="true"
- android:layout_width="match_parent"
+ android:layout_width="340dp"
android:layout_height="wrap_content"
- android:minHeight="1dp"
- android:maxHeight="1dp"
- style="@*android:style/Widget.Material.ProgressBar.Horizontal"/>
+ android:layout_gravity="center_horizontal"
+ android:visibility="gone"
+ style="@style/TrimmedHorizontalProgressBar"/>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view"
@@ -93,10 +96,9 @@
android:orientation="horizontal"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
- android:layout_marginTop="4dp"
- android:layout_marginBottom="4dp"
- android:paddingStart="19dp"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:layout_marginTop="16dp"
+ android:paddingStart="22dp"
+ android:paddingEnd="22dp">
<FrameLayout
android:layout_width="24dp"
@@ -120,7 +122,7 @@
android:gravity="start|center_vertical">
<TextView
android:id="@+id/mobile_title"
- android:layout_marginLeft="17dp"
+ android:layout_marginLeft="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@@ -131,7 +133,7 @@
android:fontFamily="google-sans"/>
<TextView
android:id="@+id/mobile_summary"
- android:layout_marginLeft="17dp"
+ android:layout_marginLeft="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@@ -161,18 +163,16 @@
<LinearLayout
android:id="@+id/turn_on_wifi_layout"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="72dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:orientation="horizontal"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
- android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingStart="22dp"
+ android:paddingEnd="22dp">
<FrameLayout
android:layout_weight="1"
@@ -219,8 +219,8 @@
android:orientation="horizontal"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
- android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingStart="22dp"
+ android:paddingEnd="22dp">
<FrameLayout
android:layout_width="24dp"
@@ -301,8 +301,8 @@
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal"
- android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingStart="22dp"
+ android:paddingEnd="22dp">
<FrameLayout
android:layout_width="24dp"
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
index cb51ab6..fb57901 100644
--- a/packages/SystemUI/res/layout/internet_list_item.xml
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -31,8 +31,8 @@
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
- android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingStart="22dp"
+ android:paddingEnd="22dp">
<FrameLayout
android:layout_width="24dp"
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 9ce83a7..8dbd59d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -82,18 +82,32 @@
<ImageView
android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_wallet_height"
- android:layout_width="@dimen/keyguard_affordance_wallet_width"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
android:layout_gravity="bottom|end"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_wallet_lockscreen"
- android:background="@drawable/wallet_lockscreen_bg"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:contentDescription="@string/accessibility_wallet_button"
android:visibility="gone" />
+ <ImageView
+ android:id="@+id/controls_button"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
+ android:layout_gravity="bottom|start"
+ android:scaleType="center"
+ android:tint="?android:attr/textColorPrimary"
+ android:src="@drawable/controls_icon"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
+ android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+ android:contentDescription="@string/quick_controls_title"
+ android:visibility="gone" />
+
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index c0d353b..075473a 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -185,7 +185,7 @@
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding"
android:layout_marginTop="-22dp"
- android:paddingBottom="0dp"
+ android:paddingBottom="2dp"
android:splitTrack="false" />
<!-- Song name -->
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_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 1086c2b..1460cdf 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -97,7 +97,7 @@
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
- <com.android.systemui.BatteryMeterView
+ <com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_height="match_parent"
android:layout_width="0dp"
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/split_shade_header.xml b/packages/SystemUI/res/layout/split_shade_header.xml
index 401dc19..f2c5b7b 100644
--- a/packages/SystemUI/res/layout/split_shade_header.xml
+++ b/packages/SystemUI/res/layout/split_shade_header.xml
@@ -78,7 +78,7 @@
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
- <com.android.systemui.BatteryMeterView
+ <com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cf91a2b..e0a51c2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,9 +55,23 @@
android:id="@+id/lock_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="48px"
- android:layout_gravity="center"
- android:scaleType="centerCrop"/>
+ android:layout_gravity="center">
+ <!-- Background protection -->
+ <ImageView
+ android:id="@+id/lock_icon_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/fingerprint_bg"
+ android:visibility="invisible"/>
+
+ <ImageView
+ android:id="@+id/lock_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="48px"
+ android:layout_gravity="center"
+ android:scaleType="centerCrop"/>
+ </com.android.keyguard.LockIconView>
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:layout_width="match_parent"
@@ -73,7 +87,12 @@
layout="@layout/keyguard_status_view"
android:visibility="gone"/>
- <include layout="@layout/dock_info_overlay" />
+ <include layout="@layout/idle_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"/>
+
+ <include layout="@layout/dock_info_overlay"/>
<FrameLayout
android:id="@+id/qs_frame"
@@ -106,6 +125,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/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 818d1d7..6d5c7d4 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -29,7 +29,7 @@
android:gravity="center_vertical"
android:orientation="horizontal"/>
- <com.android.systemui.BatteryMeterView android:id="@+id/battery"
+ <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 8834ac0..18517906 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -26,8 +26,7 @@
android:id="@+id/udfps_keyguard_fp_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/fingerprint_bg"
- android:visibility="gone"/>
+ android:src="@drawable/fingerprint_bg"/>
<!-- Fingerprint -->
<!-- AOD dashed fingerprint icon with moving dashes -->
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c5578f2..daf4fdc7 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tik weer om oop te maak"</string>
<string name="tap_again" msgid="1315420114387908655">"Tik weer"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swiep op om oop te maak"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om oop te maak"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swiep op om weer te probeer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 2e9400e..c20d01e 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/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">"Kennisgewings"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen kennisgewings nie"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofoon neem tans op"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera neem tans op"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera en mikrofoon neem tans op"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofoon het opname gestop"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera het opname gestop"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera en mikrofoon het opname gestop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4be2cee..0125b66 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ለመክፈት ዳግም መታ ያድርጉ"</string>
<string name="tap_again" msgid="1315420114387908655">"እንደገና መታ ያድርጉ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ለመክፈት በጣት ወደ ላይ ጠረግ ያድርጉ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ለመክፈት ይጫኑ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"እንደገና ለመሞከር ወደ ላይ ይጥረጉ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index 71d887d..39429e4 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ማይክሮፎን እየቀዳ ነው"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ካሜራ እየቀረጸ ነው"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ካሜራ እየቀረጸ እና ማይክሮፎን እየቀዳ ነው"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ማይክሮፎን መቅዳት አቁሟል"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ካሜራ መቅረጽ አቁሟል"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ካሜራ መቅረጽ እና ማይክሮፎን መቅዳት አቁመዋል"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 300f3c6..06bc4d5 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>
@@ -462,6 +460,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"انقر مرة أخرى للفتح"</string>
<string name="tap_again" msgid="1315420114387908655">"انقر مرة أخرى"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"يمكنك الفتح بالتمرير سريعًا لأعلى."</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"اضغط لفتح الجهاز."</string>
<string name="keyguard_retry" msgid="886802522584053523">"مرِّر سريعًا للأعلى لإعادة المحاولة."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"افتح قفل الشاشة لاستخدام تقنية NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index 769999f..13f23f0 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"جارٍ التسجيل بالميكرفون"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"جارٍ التسجيل بالكاميرا"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"جارٍ التسجيل بالكاميرا والميكروفون"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"توقف التسجيل بالميكرفون."</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"توقف التسجيل بالكاميرا."</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"توقف التسجيل بالكاميرا والميكروفون."</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b06e010..2dd3195 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"খুলিবলৈ পুনৰাই টিপক"</string>
<string name="tap_again" msgid="1315420114387908655">"পুনৰ টিপক"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"খুলিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"খুলিবলৈ টিপক"</string>
<string name="keyguard_retry" msgid="886802522584053523">"পুনৰ চেষ্টা কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 859ea2c..733e2e6 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4b9dfa5..b87b033 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Açmaq üçün yenidən tıklayın"</string>
<string name="tap_again" msgid="1315420114387908655">"Yenidən toxunun"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmaq üçün yuxarı sürüşdürün"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmaq üçün basın"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Yenidən cəhd etmək üçün yuxarı sürüşdürün"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index 1f1b649..cd8b46c 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon yazır"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera yazır"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera və mikrofon yazır"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon yazmağı dayandırıb"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera yazmağı dayandırıb"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera və mikrofon yazmağı dayandırıb"</string>
</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..93e7c0c 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da biste otvorili"</string>
<string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite nagore da biste otvorili"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite nagore da biste probali ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</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..31a37db 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,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Snimanje mikrofonom je zaustavljeno"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Snimanje kamerom je zaustavljeno"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Snimanje kamerom i mikrofonom je zaustavljeno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index aefeb47..ea4012c 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
<string name="tap_again" msgid="1315420114387908655">"Націсніце яшчэ раз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Каб адкрыць, прагарніце ўверх"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Націсніце, каб адкрыць"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Прагартайце ўверх, каб паўтарыць спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index 21a2e6e..410c120 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Ідзе запіс з выкарыстаннем мікрафона"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Ідзе запіс з выкарыстаннем камеры"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Ідзе запіс з выкарыстаннем камеры і мікрафона"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Запіс з выкарыстаннем мікрафона спынены"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Запіс з выкарыстаннем камеры спынены"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Запіс з выкарыстаннем камеры і мікрафона спынены"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 015504d..389e71a 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Докоснете отново, за да отворите"</string>
<string name="tap_again" msgid="1315420114387908655">"Докоснете отново"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Прекарайте пръст нагоре, за да отключите"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натиснете за отваряне"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Плъзнете бързо нагоре, за да опитате отново"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index b7af7cb..981ab95 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофонът записва"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камерата записва"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камерата и микрофонът записват"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофонът спря да записва"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камерата спря да записва"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камерата и микрофонът спряха да записват"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c8a4366..c856b8a 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"খোলার জন্য আবার আলতো চাপুন"</string>
<string name="tap_again" msgid="1315420114387908655">"আবার ট্যাপ করুন"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"খোলার জন্য উপরে সোয়াইপ করুন"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"আনলক করার জন্য প্রেস করুন"</string>
<string name="keyguard_retry" msgid="886802522584053523">"আবার চেষ্টা করতে উপরের দিকে সোয়াইপ করুন"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
diff --git a/packages/SystemUI/res/values-bn/strings_tv.xml b/packages/SystemUI/res/values-bn/strings_tv.xml
index 38c24ac..5d252b1 100644
--- a/packages/SystemUI/res/values-bn/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"মাইক্রোফোনে রেকর্ড করা হচ্ছে"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ক্যামেরায় রেকর্ড করা হচ্ছে"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ক্যামেরা ও মাইক্রোফোনে রেকর্ড করা হচ্ছে"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"মাইক্রোফোনে রেকর্ড করা বন্ধ হয়ে গেছে"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ক্যামেরায় রেকর্ড করা বন্ধ হয়ে গেছে"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ক্যামেরা ও মাইক্রোফোনে রেকর্ড করা বন্ধ হয়ে গেছে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 20fc2c6..83a3e14 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da otvorite"</string>
<string name="tap_again" msgid="1315420114387908655">"Ponovo dodirnite"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite da otvorite"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da otvorite"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite prema gore da pokušate ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index 01916a1..341c125 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon je prestao snimati"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera je prestala snimati"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera i mikrofon su prestali snimati"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ae12615..b008d44 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Torna a tocar per obrir-la."</string>
<string name="tap_again" msgid="1315420114387908655">"Torna a tocar"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Llisca cap amunt per obrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prem per obrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Llisca cap a dalt per tornar-ho a provar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index a060785..6a28c83 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micròfon està gravant"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La càmera està gravant"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La càmera i el micròfon estan gravant"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micròfon ha deixat de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La càmera ha deixat de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La càmera i el micròfon han deixat de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index b4937c6..ea9c4bb 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Oznámení otevřete opětovným klepnutím"</string>
<string name="tap_again" msgid="1315420114387908655">"Znovu klepněte"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Otevřete přejetím prstem nahoru"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stisknutím otevřete"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Přejetím nahoru to zkusíte znovu"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index eeab0d9..115c875 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon nahrává"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nahrává"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera a mikrofon nahrávají"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon přestal nahrávat"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera přestala nahrávat"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera a mikrofon přestaly nahrávat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 9ee6edc..bf5f367 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tryk igen for at åbne"</string>
<string name="tap_again" msgid="1315420114387908655">"Tryk igen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Stryg opad for at åbne"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryk for at åbne"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Stryg opad for at prøve igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index fb0bc2d..af48946 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/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">"Notifikationer"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen notifikationer"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen optager"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameraet optager"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameraet og mikrofonen optager"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen er stoppet med at optage"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameraet er stoppet med at optage"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameraet og mikrofonen er stoppet med at optage"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5b31275..4d66246 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
<string name="tap_again" msgid="1315420114387908655">"Noch einmal tippen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Zum Öffnen nach oben wischen"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Zum Öffnen klicken"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Zum Wiederholen nach oben wischen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index 0345c80..e8e8dcd 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon nimmt auf"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nimmt auf"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera und Mikrofon nehmen auf"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Aufnahme des Mikrofons gestoppt"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Aufnahme der Kamera gestoppt"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Aufnahme von Kamera und Mikrofon gestoppt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1c1e806..091105e0 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Πατήστε ξανά για να ανοίξετε"</string>
<string name="tap_again" msgid="1315420114387908655">"Πατήστε ξανά"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Σύρετε προς τα επάνω για άνοιγμα"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Πατήστε για άνοιγμα"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Σύρετε προς τα πάνω για να δοκιμάσετε ξανά"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index cd92772..01def2b 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Πραγματοποιείται εγγραφή από το μικρόφωνο"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Πραγματοποιείται εγγραφή από την κάμερα"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Πραγματοποιείται εγγραφή από την κάμερα και το μικρόφωνο"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Η εγγραφή από το μικρόφωνο διακόπηκε"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Η εγγραφή από την κάμερα διακόπηκε"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Η εγγραφή από την κάμερα και το μικρόφωνο διακόπηκε"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 38630e1..479ea06 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</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..b148b09 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</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..479ea06 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</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..479ea06 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</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..a3fec1d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organization"</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..166e16d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Presiona de nuevo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Presiona otra vez"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Presiona para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volver a intentarlo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
@@ -536,7 +535,7 @@
<string name="quick_settings_disclosure_named_management_vpns" msgid="4046375645500668555">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> y está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Tu organización puede controlar el tráfico de red en tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"Es posible que <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> controle el tráfico de red en tu perfil de trabajo"</string>
- <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de IT puede ver la actividad de red de tu perfil de trabajo"</string>
+ <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de TI puede ver la actividad de red de tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Es posible que la red esté supervisada"</string>
<string name="quick_settings_disclosure_vpns" msgid="7213546797022280246">"Este dispositivo está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="8117568745060010789">"Tu perfil de trabajo está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</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..f2f0601 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micrófono está grabando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La cámara está grabando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La cámara y el micrófono están grabando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micrófono dejó de grabar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La cámara dejó de grabar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La cámara y el micrófono dejaron de grabar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index bbaf208..3b06d9b 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toca de nuevo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pulsa para abrirlo"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volverlo a intentar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 4607ad5..cc78cf2 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"El micrófono está grabando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La cámara está grabando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La cámara y el micrófono están grabando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"El micrófono ha dejado de grabar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La cámara ha dejado de grabar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La cámara y el micrófono han dejado de grabar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b23b283..625b466 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Avamiseks puudutage uuesti"</string>
<string name="tap_again" msgid="1315420114387908655">"Puudutage uuesti"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pühkige avamiseks üles"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avamiseks vajutage"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Uuesti proovimiseks pühkige üles"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index 593298e..6f020c6 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon salvestab"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kaamera salvestab"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kaamera ja mikrofon salvestavad"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon peatas salvestamise"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kaamera peatas salvestamise"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kaamera ja mikrofon peatasid salvestamise"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 6344f62..fa50729 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
<string name="tap_again" msgid="1315420114387908655">"Sakatu berriro"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Sakatu irekitzeko"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index e1c4fcc..c9c30c7 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonoa grabatzen ari da"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera grabatzen ari da"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera eta mikrofonoa grabatzen ari dira"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonoak grabatzeari utzi dio"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamerak grabatzeari utzi dio"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamerak eta mikrofonoak grabatzeari utzi diote"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 6988df2..41e895b 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"دوباره ضربه بزنید تا باز شود"</string>
<string name="tap_again" msgid="1315420114387908655">"دوباره ضربه بزنید"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"برای باز کردن، انگشتتان را تند بهبالا بکشید"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"برای باز کردن فشار دهید"</string>
<string name="keyguard_retry" msgid="886802522584053523">"برای امتحان مجدد، انگشتتان را تند بهبالا بکشید"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"برای استفاده از NFC، قفل را باز کنید"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 5ad12df..3ba9b4e 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"میکروفون درحال ضبط کردن است"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"دوربین درحال ضبط کردن است"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"دوربین و میکروفون درحال ضبط کردن هستند"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ضبط میکروفون متوقف شد"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ضبط دوربین متوقف شد"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ضبط دوربین و میکروفون متوقف شد"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 29304c89..76b245f 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Avaa napauttamalla uudelleen"</string>
<string name="tap_again" msgid="1315420114387908655">"Napauta uudelleen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Avaa pyyhkäisemällä ylös"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avaa painamalla"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Yritä uudelleen pyyhkäisemällä ylös"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 61cd5ab..6312837 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofoni tallentaa"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera kuvaa"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ja mikrofoni tallentavat"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofoni lopetti tallentamisen"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera lopetti kuvaamisen"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ja mikrofoni lopettivat tallentamisen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a479e83..788a319 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Touchez à nouveau pour ouvrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toucher de nouveau"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la CCP"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</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..0925abe 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Le microphone enregistre"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"L\'appareil photo enregistre"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"L\'appareil photo et le microphone enregistrent"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Le microphone a arrêté l\'enregistrement"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"L\'appareil photo a arrêté l\'enregistrement"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"L\'appareil photo et le microphone ont arrêté l\'enregistrement"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index fef652b..645c970 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Appuyer à nouveau pour ouvrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Appuyer à nouveau"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayer vers le haut pour ouvrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 25fab4e..3a33aad 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/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">"Aucune notification"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Le micro enregistre…"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"La caméra enregistre…"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"La caméra et le micro enregistrent…"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Le micro a arrêté l\'enregistrement"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"La caméra a arrêté l\'enregistrement"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"La caméra et le micro ont arrêté l\'enregistrement"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9e91ae5..88098a0 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toca de novo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toca de novo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasa o dedo cara arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Preme para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Pasa o dedo cara arriba para tentalo de novo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización."</string>
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index cd12b94..679c21d 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O micrófono está gravando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A cámara está gravando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A cámara e o micrófono están gravando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O micrófono deixou de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A cámara deixou de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A cámara e o micrófono deixaron de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e099447..2f09896 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -230,7 +230,7 @@
<string name="accessibility_battery_level" msgid="5143715405241138822">"બૅટરી <xliff:g id="NUMBER">%d</xliff:g> ટકા."</string>
<string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"તમારા વપરાશના આધારે બૅટરી <xliff:g id="PERCENTAGE">%1$s</xliff:g> ટકા, જે લગભગ <xliff:g id="TIME">%2$s</xliff:g> સુધી ચાલે તેટલી બચી છે"</string>
<string name="accessibility_battery_level_charging" msgid="8892191177774027364">"બૅટરી ચાર્જ થઈ રહી છે, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
- <string name="accessibility_settings_button" msgid="2197034218538913880">"સિસ્ટમ સેટિંગ્સ."</string>
+ <string name="accessibility_settings_button" msgid="2197034218538913880">"સિસ્ટમ સેટિંગ."</string>
<string name="accessibility_notifications_button" msgid="3960913924189228831">"નોટિફિકેશન."</string>
<string name="accessibility_overflow_action" msgid="8555835828182509104">"બધી સૂચના જુઓ"</string>
<string name="accessibility_remove_notification" msgid="1641455251495815527">"સૂચના સાફ કરો."</string>
@@ -245,7 +245,7 @@
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"સૂચના કાઢી નાખી."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
- <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ્સ."</string>
+ <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
<string name="accessibility_desc_settings" msgid="6728577365389151969">"સેટિંગ"</string>
<string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"ઝલક."</string>
@@ -315,7 +315,7 @@
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> વધુ સૂચના અંદર છે.</item>
</plurals>
<string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
- <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"સૂચનાઓની સેટિંગ્સ"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"નોટિફિકેશન સેટિંગ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> સેટિંગ"</string>
<string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"સ્ક્રીન ઑટોમૅટિક રીતે ફરશે."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"સ્ક્રીન લેન્ડસ્કેપ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
@@ -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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ખોલવા માટે ફરીથી ટૅપ કરો"</string>
<string name="tap_again" msgid="1315420114387908655">"ફરીથી ટૅપ કરો"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ખોલવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"અનલૉક કરવા માટે દબાવો"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ફરી પ્રયાસ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
@@ -567,12 +566,12 @@
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"તમારી વ્યક્તિગત પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ડિવાઇસ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા મેનેજ થાય છે."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
- <string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સંબંદ્ધ ડેટા અને ઉપકરણની સ્થાન માહિતીનું નિરીક્ષણ અને સંચાલન કરી શકે છે."</string>
+ <string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સંબંધિત ડેટા અને ડિવાઇસની સ્થાન માહિતીને મૉનિટર અને મેનેજ કરી શકે છે."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"વધુ જાણો"</string>
<string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
- <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPNની સેટિંગ્સ ખોલો"</string>
+ <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN સેટિંગ ખોલો"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"વિશ્વસનીય ઓળખપત્ર ખોલો"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યુ છે, જે તમારા ઉપકરણ પર ટ્રાફિકનું નિરીક્ષણ કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
@@ -619,7 +618,7 @@
<string name="screen_pinning_start" msgid="7483998671383371313">"ઍપ પિન કરી"</string>
<string name="screen_pinning_exit" msgid="4553787518387346893">"ઍપ અનપિન કરી"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
- <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"તે સેટિંગ્સમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
+ <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"તે સેટિંગમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"છુપાવો"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"કૉલ કરો"</string>
<string name="stream_system" msgid="7663148785370565134">"સિસ્ટમ"</string>
@@ -657,7 +656,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"સિસ્ટમ UI ટ્યૂનર"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"એમ્બેડ કરેલ બૅટરી ટકા બતાવો"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"જ્યારે ચાર્જ ન થઈ રહ્યું હોય ત્યારે સ્ટેટસ બાર આયકનની અંદર બૅટરી સ્તર ટકા બતાવો"</string>
- <string name="quick_settings" msgid="6211774484997470203">"ઝડપી સેટિંગ્સ"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"ઝડપી સેટિંગ"</string>
<string name="status_bar" msgid="4357390266055077437">"સ્ટેટસ બાર"</string>
<string name="overview" msgid="3522318590458536816">"ઝલક"</string>
<string name="demo_mode" msgid="263484519766901593">"સિસ્ટમ UI ડેમો મોડ"</string>
@@ -682,21 +681,21 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ્સ, <xliff:g id="TITLE">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"હૉટસ્પૉટ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string>
<string name="tuner_warning" msgid="1861736288458481650">"સિસ્ટમ UI ટ્યૂનર તમને Android વપરાશકર્તા ઇન્ટરફેસને ટ્વીક અને કસ્ટમાઇઝ કરવાની વધારાની રીતો આપે છે. ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string>
<string name="got_it" msgid="477119182261892069">"સમજાઈ ગયું"</string>
- <string name="tuner_toast" msgid="3812684836514766951">"અભિનંદન! સિસ્ટમ UI ટ્યૂનરને સેટિંગ્સમાં ઉમેરવામાં આવ્યું છે"</string>
- <string name="remove_from_settings" msgid="633775561782209994">"સેટિંગ્સમાંથી દૂર કરો"</string>
- <string name="remove_from_settings_prompt" msgid="551565437265615426">"સેટિંગ્સમાંથી સિસ્ટમ UI ટ્યૂનર દૂર કરી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
+ <string name="tuner_toast" msgid="3812684836514766951">"અભિનંદન! સિસ્ટમ UI ટ્યૂનરને સેટિંગમાં ઉમેરવામાં આવ્યું છે"</string>
+ <string name="remove_from_settings" msgid="633775561782209994">"સેટિંગમાંથી કાઢી નાખો"</string>
+ <string name="remove_from_settings_prompt" msgid="551565437265615426">"સેટિંગમાંથી સિસ્ટમ UI ટ્યૂનર કાઢી નાખી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
<string name="activity_not_found" msgid="8711661533828200293">"તમારા ઉપકરણ પર ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
<string name="clock_seconds" msgid="8709189470828542071">"ઘડિયાળ સેકન્ડ બતાવો"</string>
<string name="clock_seconds_desc" msgid="2415312788902144817">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
- <string name="qs_rearrange" msgid="484816665478662911">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
- <string name="show_brightness" msgid="6700267491672470007">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
+ <string name="qs_rearrange" msgid="484816665478662911">"ઝડપી સેટિંગને ફરીથી ગોઠવો"</string>
+ <string name="show_brightness" msgid="6700267491672470007">"ઝડપી સેટિંગમાં બ્રાઇટનેસ બતાવો"</string>
<string name="experimental" msgid="3549865454812314826">"પ્રાયોગિક"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"બ્લૂટૂથ ચાલુ કરવુ છે?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં બ્લૂટૂથ ચાલુ કરવાની જરૂર પડશે."</string>
@@ -918,19 +917,19 @@
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ટાઇલ ઉમેરી"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ટાઇલ કાઢી નાખી"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ્સ સંપાદક."</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ એડિટર."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> નોટિફિકેશન: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ઝડપી સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ઝડપી સેટિંગ્સ બંધ કરો."</string>
+ <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ઝડપી સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ઝડપી સેટિંગ બંધ કરો."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"એલાર્મ સેટ કર્યો."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> તરીકે સાઇન ઇન કર્યું"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"વપરાશકર્તા પસંદ કરો"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"કોઈ ઇન્ટરનેટ નથી"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"વિગતો ખોલો."</string>
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"<xliff:g id="REASON">%s</xliff:g>ને કારણે અનુપલબ્ધ છે"</string>
- <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
- <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
+ <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ ખોલો."</string>
+ <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગના ક્રમમાં ફેરફાર કરો."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
@@ -988,7 +987,7 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"મોબાઇલ ડેટા બંધ કરીએ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"તમને <xliff:g id="CARRIER">%s</xliff:g> મારફતે ડેટા અથવા ઇન્ટરનેટનો ઍક્સેસ મળશે નહીં. ઇન્ટરનેટ માત્ર વાઇ-ફાઇ દ્વારા ઉપલબ્ધ થશે."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"તમારા કૅરિઅર"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"એક ઍપ પરવાનગી વિનંતીને અસ્પષ્ટ કરતી હોવાને કારણે, સેટિંગ્સ તમારા પ્રતિસાદને ચકાસી શકતી નથી."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"કોઈ ઍપ પરવાનગી વિનંતીને અસ્પષ્ટ કરતી હોવાને કારણે, સેટિંગ તમારા પ્રતિસાદને ચકાસી શકતું નથી."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- મારાથી <xliff:g id="APP">%1$s</xliff:g>ની માહિતી વાંચી શકાતી નથી"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- મારાથી <xliff:g id="APP">%1$s</xliff:g>ની અંદર ક્રિયાઓ કરી શકાતી નથી"</string>
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index a53e983..e226503 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"કૅમેરાનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"કૅમેરાનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index fde2a39..9b6ce4f 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"खोलने के लिए फिर से टैप करें"</string>
<string name="tap_again" msgid="1315420114387908655">"फिर से टैप करें"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"खोलने के लिए ऊपर स्वाइप करें"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलॉक करने के लिए दबाएं"</string>
<string name="keyguard_retry" msgid="886802522584053523">"फिर से कोशिश करने के लिए ऊपर की ओर स्वाइप करें"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index fedaae3..cc9a562 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफ़ोन रिकॉर्ड कर रहा है"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"कैमरा रिकॉर्ड कर रहा है"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कैमरा और माइक्रोफ़ोन रिकॉर्ड कर रहे हैं"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कैमरे ने रिकॉर्ड करना बंद कर दिया है"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कैमरे और माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bbba1a8..2892e66 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite opet za otvaranje"</string>
<string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prijeđite prstom prema gore da biste otvorili"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Prijeđite prstom prema gore za ponovni pokušaj"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 3bfdf70..633847c 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon snima"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera snima"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera i mikrofon snimaju"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon je prestao snimati"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera je prestala snimati"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera i mikrofon prestali su snimati"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7eb5ec1..079c915 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Koppintson ismét a megnyitáshoz"</string>
<string name="tap_again" msgid="1315420114387908655">"Koppintson újra"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Csúsztasson felfelé a megnyitáshoz"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"A megnyitáshoz nyomja meg"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Az újrapróbálkozáshoz csúsztassa felfelé az ujját"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index 91183af..97c375a 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"A mikrofon felvételt készít…"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A kamera felvételt készít…"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A kamera és a mikrofon felvételt készít…"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"A mikrofon befejezte a felvételkészítést"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A kamera befejezte a felvételkészítést"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A kamera és a mikrofon befejezte a felvételkészítést"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 95b2d6a..7df2efb 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Կրկին հպեք՝ բացելու համար"</string>
<string name="tap_again" msgid="1315420114387908655">"Նորից հպեք"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Բացելու համար սահեցրեք վերև"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Սեղմեք՝ բացելու համար"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Սահեցրեք վերև՝ նորից փորձելու համար"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index cf4eb90..3f46b90 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Խոսափողը ձայնագրում է"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Տեսախցիկը տեսագրում է"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Տեսախցիկն ու խոսափողը տեսաձայնագրում են"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Խոսափողն այլևս չի ձայնագրում"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Տեսախցիկն այլևս չի տեսագրում"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Տեսախցիկն ու խոսափողը այլևս չեն տեսաձայնագրում"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 193628a..07a5672 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ketuk lagi untuk membuka"</string>
<string name="tap_again" msgid="1315420114387908655">"Ketuk lagi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Geser ke atas untuk membuka"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk membuka"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Geser ke atas untuk mencoba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index 3b446ad..d58cdc8 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon sedang merekam"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera sedang merekam"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera dan Mikrofon sedang merekam"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon berhenti merekam"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera berhenti merekam"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera dan Mikrofon berhenti merekam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index dbc7c05..fbcbddb 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ýttu aftur til að opna"</string>
<string name="tap_again" msgid="1315420114387908655">"Ýttu aftur"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Strjúktu upp til að opna"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ýttu til að opna"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Strjúktu upp til að reyna aftur"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index 7c23e62..eb0f450 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Hljóðnemi er að taka upp"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Myndavél er að taka upp"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Myndavél og hljóðnemi eru að taka upp"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Hljóðnemi er hættur að taka upp"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Myndavél er hætt að taka upp"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Myndavél og hljóðnemi eru hætt að taka upp"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6f160b9..52b5879 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tocca ancora per aprire"</string>
<string name="tap_again" msgid="1315420114387908655">"Tocca di nuovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Scorri verso l\'alto per aprire"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Premi per aprire"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Scorri verso l\'alto per riprovare"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 57931b0..45d3369 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Registrazione in corso con il microfono"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Registrazione in corso con la fotocamera"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Registrazione in corso con fotocamera e microfono"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Registrazione con il microfono interrotta"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Registrazione con la fotocamera interrotta"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Registrazione con fotocamera e microfono interrotta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9dccc98..7dce350 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"יש להקיש שוב כדי לפתוח את ההתראה"</string>
<string name="tap_again" msgid="1315420114387908655">"צריך להקיש פעם נוספת"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"צריך להחליק כדי לפתוח"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"יש להקיש כדי לפתוח"</string>
<string name="keyguard_retry" msgid="886802522584053523">"יש להחליק למעלה כדי לנסות שוב"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index f01321e..5c091d3 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"המיקרופון מקליט"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"המצלמה מקליטה"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"המצלמה והמיקרופון מקליטים"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"המיקרופון הפסיק להקליט"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"המצלמה הפסיקה להקליט"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"המצלמה והמיקרופון הפסיקו להקליט"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1e8020f..47aabbb 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"開くにはもう一度タップしてください"</string>
<string name="tap_again" msgid="1315420114387908655">"もう一度タップしてください"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"開くには上にスワイプします"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"押すと開きます"</string>
<string name="keyguard_retry" msgid="886802522584053523">"上にスワイプしてもう一度お試しください"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 7f676b5..c37958f 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"マイクで録音しています"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"カメラで録画しています"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"カメラとマイクで録画、録音しています"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"マイクが録音を停止しました"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"カメラが録画を停止しました"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"カメラとマイクが録画、録音を停止しました"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 8177464..4b9ab21 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"შეეხეთ ისევ გასახსნელად"</string>
<string name="tap_again" msgid="1315420114387908655">"შეეხეთ ხელახლა"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"გასახსნელად გადაფურცლეთ ზემოთ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"დააჭირეთ გასახსნელად"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ხელახლა საცდელად გადაფურცლეთ ზემოთ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index 0819781..8db4b1b 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"მიკროფონი იწერს"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"კამერა იწერს"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"კამერა და მიკროფონი იწერს"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"მიკროფონმა ჩაწერა შეწყვიტა"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"კამერამ ჩაწერა შეწყვიტა"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"კამერამ და მიკროფონმა ჩაწერა შეწყვიტა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 983e4b8..e9d6067 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ашу үшін қайта түртіңіз"</string>
<string name="tap_again" msgid="1315420114387908655">"Қайта түртіңіз."</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ашу үшін жоғары қарай сырғытыңыз."</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ашу үшін басыңыз."</string>
<string name="keyguard_retry" msgid="886802522584053523">"Әрекетті қайталау үшін жоғары сырғытыңыз."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 768e3ac..a56b4aa 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон жазып жатыр."</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера жазып жатыр."</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера мен микрофон жазып жатыр."</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон жазуды тоқтатты."</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера жазуды тоқтатты."</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера мен микрофон жазуды тоқтатты."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 183712b..52d91f3 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ប៉ះម្ដងទៀត ដើម្បីបើក"</string>
<string name="tap_again" msgid="1315420114387908655">"ចុចម្ដងទៀត"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"អូសឡើងលើដើម្បីបើក"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ចុច ដើម្បីបើក"</string>
<string name="keyguard_retry" msgid="886802522584053523">"អូសឡើងលើ ដើម្បីព្យាយាមម្ដងទៀត"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក"</string>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index 0dec2d6..c654e6d 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"មីក្រូហ្វូនកំពុងថត"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"កាមេរ៉ាកំពុងថត"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"កាមេរ៉ា និងមីក្រូហ្វូនកំពុងថត"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"មីក្រូហ្វូនបានឈប់ថត"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"កាមេរ៉ាបានឈប់ថត"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"កាមេរ៉ា និងមីក្រូហ្វូនបានឈប់ថត"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e48c842..f23153d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ತೆರೆಯಲು ಮತ್ತೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="tap_again" msgid="1315420114387908655">"ಪುನಃ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ತೆರೆಯಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ತೆರೆಯಲು ಒತ್ತಿ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index ef10e3a..3955a09 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ಕ್ಯಾಮರಾ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿವೆ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಿದೆ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ಕ್ಯಾಮರಾ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಲಾಗಿದೆ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸಿವೆ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6f896c7..3344ddc 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -353,7 +353,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"위치 사용 중지"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"허용됨"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"사용 가능"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"차단됨"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"미디어 기기"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
@@ -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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"다시 탭하여 열기"</string>
<string name="tap_again" msgid="1315420114387908655">"다시 탭하세요."</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"위로 스와이프하여 열기"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"열려면 누르세요"</string>
<string name="keyguard_retry" msgid="886802522584053523">"위로 스와이프하여 다시 시도해 주세요"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index f9c723a..b9fb537 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"마이크 녹음 중"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"카메라 녹화 중"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"카메라 녹화 및 마이크 녹음 중"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"마이크 녹음 중단됨"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"카메라 녹화 중단됨"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"카메라 녹화 및 마이크 녹음 중단됨"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 38c0185..b583f24 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -48,8 +48,8 @@
</string-array>
<string-array name="tile_states_battery">
<item msgid="6311253873330062961">"이용 불가"</item>
- <item msgid="7838121007534579872">"꺼짐"</item>
- <item msgid="1578872232501319194">"켜짐"</item>
+ <item msgid="7838121007534579872">"사용 안함"</item>
+ <item msgid="1578872232501319194">"사용"</item>
</string-array>
<string-array name="tile_states_dnd">
<item msgid="467587075903158357">"이용 불가"</item>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 20ec715..f7a40b6 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ачуу үчүн кайра таптап коюңуз"</string>
<string name="tap_again" msgid="1315420114387908655">"Кайра таптап коюңуз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ачуу үчүн өйдө сүрүңүз"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ачуу үчүн басыңыз"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Кайталоо үчүн экранды өйдө сүрүңүз"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
@@ -1019,8 +1018,8 @@
<string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Жылдыруу"</string>
- <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
- <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
+ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, жөндөөлөргө өтүңүз."</string>
+ <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн жөндөөлөргө өтүңүз"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string>
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index 1dba865..52b2375 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон жаздырууда"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера жаздырууда"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера менен микрофон жаздырууда"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон жаздырууну токтотту"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера жаздырууну токтотту"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера менен микрофон жаздырууну токтотту"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index de3afd3..d2ac9ef 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ແຕະອີກຄັ້ງເພື່ອເປີດ"</string>
<string name="tap_again" msgid="1315420114387908655">"ແຕະອີກເທື່ອໜຶ່ງ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ປັດຂຶ້ນເພື່ອເປີດ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ກົດເພື່ອເປີດ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ປັດຂຶ້ນເພື່ອລອງໃໝ່"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index a45fb45..d2de125 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ໄມໂຄຣໂຟນກຳລັງບັນທຶກ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ກ້ອງຖ່າຍຮູບກຳລັງບັນທຶກ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນກຳລັງບັນທຶກ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ໄມໂຄຣໂຟນຢຸດການບັນທຶກແລ້ວ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ກ້ອງຖ່າຍຮູບຢຸດການບັນທຶກແລ້ວ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຢຸດການບັນທຶກແລ້ວ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 230ee19..3101235 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Palieskite dar kartą, kad atidarytumėte"</string>
<string name="tap_again" msgid="1315420114387908655">"Palieskite dar kartą"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Perbraukite aukštyn, kad atidarytumėte"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Paspauskite, kad atidarytumėte"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Jei norite bandyti dar kartą, perbraukite aukštyn"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 8c329f9..df23a61 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonas įrašo"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera įrašo"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ir mikrofonas įrašo"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonas nebeįrašo"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera nebeįrašo"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ir mikrofonas nebeįrašo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c454f2a..9c58eaf 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Pieskarieties vēlreiz, lai atvērtu"</string>
<string name="tap_again" msgid="1315420114387908655">"Pieskarieties vēlreiz"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Velciet augšup, lai atvērtu"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nospiediet, lai atvērtu"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Velciet augšup, lai mēģinātu vēlreiz"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index 758d28c..e343a77 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Notiek ierakstīšana ar mikrofonu"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Notiek ierakstīšana ar kameru"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Notiek ierakstīšana ar kameru un mikrofonu"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Ierakstīšana ar mikrofonu apturēta"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ierakstīšana ar kameru apturēta"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ierakstīšana ar kameru un mikrofonu apturēta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index fc1a69a..fc14cba 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -243,7 +243,7 @@
<skip />
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
- <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено."</string>
+ <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
@@ -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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Допрете повторно за да се отвори"</string>
<string name="tap_again" msgid="1315420114387908655">"Допрете повторно"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Повлечете за да отворите"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притиснете за да отворите"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Повлечете нагоре за да се обидете повторно"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index 0dfbd79..f39f1fa 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофонот снима"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камерата снима"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камерата и микрофонот снимаат"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофонот прекина со снимање"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камерата прекина со снимање"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камерата и микрофонот прекинаа со снимање"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1c3837f..4f90802 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"തുറക്കുന്നതിന് വീണ്ടും ടാപ്പുചെയ്യുക"</string>
<string name="tap_again" msgid="1315420114387908655">"വീണ്ടും ടാപ്പ് ചെയ്യുക"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"തുറക്കാൻ മുകളിലോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"തുറക്കാൻ അമർത്തുക"</string>
<string name="keyguard_retry" msgid="886802522584053523">"വീണ്ടും ശ്രമിക്കാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index 70cced8..50d0280 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"മൈക്രോഫോൺ റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ക്യാമറ റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ക്യാമറയും മൈക്രോഫോണും റെക്കോർഡ് ചെയ്യുകയാണ്"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"മൈക്രോഫോൺ റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ക്യാമറ റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ക്യാമറയും മൈക്രോഫോണും റെക്കോർഡ് ചെയ്യുന്നത് നിർത്തി"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4e04c61..b079d86 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Нээхийн тулд дахин товшино уу"</string>
<string name="tap_again" msgid="1315420114387908655">"Дaхин товшино уу"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Нээхийн тулд дээш шударна уу"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нээхийн тулд дарна уу"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Дахин оролдохын тулд дээш шударна уу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index 221d8ae..1b20d84 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон бичиж байна"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камер бичиж байна"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камер болон микрофон бичиж байна"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Микрофон бичихээ зогсоосон"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камер бичихээ зогсоосон"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камер болон микрофон бичихээ зогсоосон"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5785b41..0e8de95 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string>
<string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"उघडण्यासाठी दाबा"</string>
<string name="keyguard_retry" msgid="886802522584053523">"पुन्हा प्रयत्न करण्यासाठी वर स्वाइप करा"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index ac0cad1..2d79d4a 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"मायक्रोफोन रेकॉर्ड करत आहे"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"कॅमेरा रेकॉर्ड करत आहे"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कॅमेरा आणि मायक्रोफोन रेकॉर्ड करत आहेत"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"मायक्रोफोनने रेकॉर्ड करणे थांबवले"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कॅमेराने रेकॉर्ड करणे थांबवले"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कॅमेरा आणि मायक्रोफोनने रेकॉर्ड करणे थांबवले"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6b6a6b7..955754a 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ketik lagi untuk membuka"</string>
<string name="tap_again" msgid="1315420114387908655">"Ketik sekali lagi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Leret ke atas untuk buka"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk buka"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Leret ke atas untuk mencuba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index 46e345e..9064ec4 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon sedang merakam"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera sedang merakam"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera dan Mikrofon sedang merakam"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon berhenti merakam"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera berhenti merakam"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera dan Mikrofon berhenti merakam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ba643f0..968f6db 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ဖွင့်ရန် ထပ်ပြီး ပုတ်ပါ"</string>
<string name="tap_again" msgid="1315420114387908655">"ထပ်တို့ပါ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ဖွင့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ဖွင့်ရန် နှိပ်ပါ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ထပ်စမ်းကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index 268c554..1aca9eb 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"မိုက်ခရိုဖုန်း မှတ်တမ်းတင်နေသည်"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ကင်မရာ မှတ်တမ်းတင်နေသည်"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းက မှတ်တမ်းတင်နေသည်"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"မိုက်ခရိုဖုန်း မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ကင်မရာ မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းက မှတ်တမ်းတင်ခြင်းကို ရပ်ထားသည်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7a42d3e..1f8a01b 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Trykk på nytt for å åpne"</string>
<string name="tap_again" msgid="1315420114387908655">"Trykk igjen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Sveip opp for å åpne"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Trykk for å åpne"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Sveip opp for å prøve igjen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index c5767dd..7eb6a29 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/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">"Varsler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen varsler"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen tar opp"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameraet tar opp"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameraet og mikrofonen tar opp"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen stoppet opptaket"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameraet stoppet opptaket"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameraet og mikrofonen stoppet opptaket"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c46d705..a142df8 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>
@@ -454,6 +452,8 @@
<string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
<string name="tap_again" msgid="1315420114387908655">"फेरि ट्याप गर्नुहोस्"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string>
+ <!-- no translation found for keyguard_unlock_press (8488350566398524740) -->
+ <skip />
<string name="keyguard_retry" msgid="886802522584053523">"फेरि प्रयास गर्न माथितिर स्वाइप गर्नुहोस्"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"यो डिभाइस तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 925f7b76..410f26f 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफोनले रेकर्ड गर्दै छ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"क्यामेराले रेकर्ड गर्दै छ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"क्यामेरा र माइक्रोफोनले रेकर्ड गर्दै छन्"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफोनले रेकर्ड गर्न छाड्यो"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"क्यामेराले रेकर्ड गर्न छाड्यो"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"क्यामेरा र माइक्रोफोनले रेकर्ड गर्न छाडे"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index f0cc269..e751512 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tik nog eens om te openen"</string>
<string name="tap_again" msgid="1315420114387908655">"Tik nog een keer"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om te openen"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 22d3b88..7aeeabf 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/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">"Meldingen"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen meldingen"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microfoon neemt op"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera neemt op"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera en microfoon nemen op"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microfoon neemt niet meer op"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera neemt niet meer op"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera en microfoon nemen niet meer op"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 2fcc505..5763a34 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ଖୋଲିବା ପାଇଁ ପୁଣି ଟାପ୍ କରନ୍ତୁ"</string>
<string name="tap_again" msgid="1315420114387908655">"ପୁଣି ଟାପ୍ କରନ୍ତୁ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ଖୋଲିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ଖୋଲିବାକୁ ଦବାନ୍ତୁ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ପୁଣି ଚେଷ୍ଟା କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
diff --git a/packages/SystemUI/res/values-or/strings_tv.xml b/packages/SystemUI/res/values-or/strings_tv.xml
index 707c49e..2669a5a 100644
--- a/packages/SystemUI/res/values-or/strings_tv.xml
+++ b/packages/SystemUI/res/values-or/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"କ୍ୟାମେରା ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ କରୁଛି"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"କ୍ୟାମେରା ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନ୍ ରେକର୍ଡିଂ ବନ୍ଦ କରିଛି"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3dad773..0fe6f8a 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ਖੋਲ੍ਹਣ ਲਈ ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
<string name="tap_again" msgid="1315420114387908655">"ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ਖੋਲ੍ਹਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ"</string>
<string name="keyguard_retry" msgid="886802522584053523">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਉੱਤੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index c076194..3443cfa 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਰਿਕਾਰਡ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"ਕੈਮਰਾ ਰਿਕਾਰਡ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਰਿਕਾਰਡ ਕਰ ਰਹੇ ਹਨ"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"ਕੈਮਰੇ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"ਕੈਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੇ ਰਿਕਾਰਡ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 30d6f05..220cd80 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Kliknij ponownie, by otworzyć"</string>
<string name="tap_again" msgid="1315420114387908655">"Kliknij jeszcze raz"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Przesuń w górę, by otworzyć"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Naciśnij, by otworzyć"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Przesuń w górę, by spróbować ponownie"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index e63aade..12b3777 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon rejestruje"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Aparat rejestruje"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Aparat i mikrofon rejestrują"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon przestał rejestrować"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Aparat przestał rejestrować"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Aparat i mikrofon przestały rejestrować"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 24015d8..39911ca 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</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..d475e5d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize rapidamente para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prima para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize rapidamente para cima para tentar novamente."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</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..3ae7daf 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O microfone está a gravar"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A câmara está a gravar"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A câmara e o microfone estão a gravar"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O microfone parou a gravação"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A câmara parou a gravação"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A câmara e o microfone pararam a gravação"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 24015d8..39911ca 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</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..26a8cce 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Atingeți din nou pentru a deschide"</string>
<string name="tap_again" msgid="1315420114387908655">"Atingeți din nou"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Glisați în sus pentru a deschide"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Apăsați pentru a deschide"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Glisați pentru a încerca din nou"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index c64a492..54dd985 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microfonul înregistrează"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera foto înregistrează"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera foto și microfonul înregistrează"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microfonul nu mai înregistrează"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera foto a oprit înregistrarea"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera foto și microfonul nu mai înregistrează"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7ebbb43..533b81c 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Нажмите ещё раз, чтобы открыть"</string>
<string name="tap_again" msgid="1315420114387908655">"Нажмите ещё раз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведите вверх, чтобы открыть"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нажмите, чтобы открыть."</string>
<string name="keyguard_retry" msgid="886802522584053523">"Чтобы повторить попытку, проведите вверх"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index 8ce0dc2..befb5d2 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Выполняется запись с микрофона"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Выполняется запись с камеры"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Выполняется запись с камеры и микрофона"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Запись с микрофона остановлена"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Запись с камеры остановлена"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Запись с камеры и микрофона остановлена"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 6cf9f9b..63baa6d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string>
<string name="tap_again" msgid="1315420114387908655">"නැවත තට්ටු කරන්න"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"විවෘත කිරීමට ස්වයිප් කරන්න"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"විවෘත කිරීමට ඔබන්න"</string>
<string name="keyguard_retry" msgid="886802522584053523">"නැවත උත්සාහ කිරීමට ඉහළට ස්වයිප් කරන්න"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index 3067be3..92257c7 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"මයික්රෆෝනය පටිගත කරයි"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"කැමරාව පටිගත කරයි"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"කැමරාව සහ මයික්රෆෝනය පටිගත කරයි"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"මයික්රෆෝනය පටිගත කිරීම නැවැත්වීය"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"කැමරාව පටිගත කිරීම නැවැත්වීය"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"කැමරාව සහ මයික්රෆෝනය පටිගත කිරීම නැවැත්වීය"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5893223..3a22085 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Upozornenie otvoríte opätovným klepnutím"</string>
<string name="tap_again" msgid="1315420114387908655">"Klepnite znova"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Otvorte potiahnutím prstom nahor"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stlačením otvoríte"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Potiahnutím nahor to skúste znova"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index b37648d..6910079 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofón nahráva"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera nahráva"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera a mikrofón nahrávajú"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofón prestal nahrávať"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera prestala nahrávať"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera a mikrofón prestali nahrávať"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 6bc27d0..5b8f826 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Znova se dotaknite, da odprete"</string>
<string name="tap_again" msgid="1315420114387908655">"Znova se dotaknite možnosti"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Povlecite navzgor, da odprete"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite, če želite odpreti."</string>
<string name="keyguard_retry" msgid="886802522584053523">"Povlecite navzgor za vnovičen poskus"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 1f66138..1005079 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Snemanje z mikrofonom"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Snemanje s fotoaparatom"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Snemanje s fotoaparatom in mikrofonom"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Ustavljeno snemanje z mikrofonom"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ustavljeno snemanje s fotoaparatom"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ustavljeno snemanje s fotoaparatom in mikrofonom"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 1600d03..dab0895 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>
@@ -454,6 +452,8 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Trokit përsëri për ta hapur"</string>
<string name="tap_again" msgid="1315420114387908655">"Trokit sërish"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string>
+ <!-- no translation found for keyguard_unlock_press (8488350566398524740) -->
+ <skip />
<string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
diff --git a/packages/SystemUI/res/values-sq/strings_tv.xml b/packages/SystemUI/res/values-sq/strings_tv.xml
index fb74e38..c5ce631 100644
--- a/packages/SystemUI/res/values-sq/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"\"Mikrofoni\" po regjistron"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"\"Kamera\" po regjistron"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"\"Kamera\" dhe \"Mikrofoni\" po regjistrojnë"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"\"Mikrofoni\" ndaloi së regjistruari"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"\"Kamera\" ndaloi së regjistruari"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"\"Kamera\" dhe \"Mikrofoni\" ndaluan së regjistruari"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0670a9c..e5ec321 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>
@@ -456,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Додирните поново да бисте отворили"</string>
<string name="tap_again" msgid="1315420114387908655">"Додирните поново"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Превуците нагоре да бисте отворили"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притисните да бисте отворили"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Превуците нагоре да бисте пробали поново"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index 59151da..d35ff3c 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Микрофон снима"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера снима"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера и микрофон снимају"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Снимање микрофоном је заустављено"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Снимање камером је заустављено"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Снимање камером и микрофоном је заустављено"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4ba8999..e7b41f5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -158,21 +158,21 @@
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Använd pinkod"</string>
- <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd grafiskt lösenord"</string>
+ <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd mönster"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Använd lösenord"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Fel pinkod"</string>
- <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Fel grafiskt lösenord"</string>
+ <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Fel mönster"</string>
<string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Fel lösenord"</string>
<string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"För många felaktiga försök.\nFörsök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Försök igen. Försök <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> av <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
<string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Din data raderas."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Enhetens data raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Enhetens data raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Enhetens data raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Enhetens data raderas om du anger fel lösenord vid nästa försök."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Användaren raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Användaren raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Användaren raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Den här användaren raderas om du anger fel lösenord vid nästa försök."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du anger fel grafiskt lösenord vid nästa försök."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du ritar fel mönster vid nästa försök."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jobbprofilen och dess data raderas om du anger fel pinkod vid nästa försök."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Din jobbprofil och dess data raderas om du anger fel lösenord vid nästa försök."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"För många felaktiga försök. Enhetens data raderas."</string>
@@ -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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tryck igen för att öppna"</string>
<string name="tap_again" msgid="1315420114387908655">"Tryck igen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Öppna genom att svepa uppåt"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryck för att öppna"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Svep uppåt om du vill försöka igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index fd8fa4b..346d5d2 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/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">"Aviseringar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Inga aviseringar"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofonen spelar in"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kameran spelar in"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kameran och mikrofonen spelar in"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofonen slutade spela in"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kameran slutade spela in"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kameran och mikrofonen slutade spelade in"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0ba5d05..f58abab 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Gusa tena ili ufungue"</string>
<string name="tap_again" msgid="1315420114387908655">"Gusa tena"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Telezesha kidole juu ili ufungue"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Bofya ili ufungue"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Telezesha kidole juu ili ujaribu tena"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 8f6880d..a585e69 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Maikrofoni inarekodi"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera inarekodi"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera na Maikrofoni zinarekodi"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Maikrofoni imeacha kurekodi"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera imeacha kurekodi"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera na Maikrofoni zimeacha kurekodi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 369e45c..ab159e1 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,10 +18,18 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
- <integer name="quick_settings_num_columns">2</integer>
+ <!-- The maximum number of rows in the QuickQSPanel -->
<integer name="quick_qs_panel_max_rows">4</integer>
+
+ <!-- The maximum number of tiles in the QuickQSPanel -->
<integer name="quick_qs_panel_max_tiles">8</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">2</integer>
+
+ <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+ <bool name="config_skinnyNotifsInLandscape">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 942cb2b..45b5afa 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -40,4 +40,8 @@
<!-- How many lines to show in the security footer -->
<integer name="qs_security_footer_maxLines">1</integer>
+
+ <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
+ <bool name="allow_force_nav_bar_handle_opaque">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 4de2ab5..ac21044 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"திறக்க, மீண்டும் தட்டவும்"</string>
<string name="tap_again" msgid="1315420114387908655">"மீண்டும் தட்டவும்"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"திறப்பதற்கு மேல் நோக்கி ஸ்வைப் செய்யவும்"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"திறப்பதற்கு அழுத்தவும்"</string>
<string name="keyguard_retry" msgid="886802522584053523">"மீண்டும் முயல மேல்நோக்கி ஸ்வைப் செய்யவும்"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 9c62d8cf..1dc581d 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"மைக்ரோஃபோன் ரெக்கார்டு செய்கிறது"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"கேமரா ரெக்கார்டு செய்கிறது"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"கேமராவும் மைக்ரோஃபோனும் ரெக்கார்டு செய்கின்றன"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"மைக்ரோஃபோன் ரெக்கார்டு செய்வதை நிறுத்திவிட்டது"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"கேமரா ரெக்கார்டு செய்வதை நிறுத்திவிட்டது"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"கேமராவும் மைக்ரோஃபோனும் ரெக்கார்டு செய்வதை நிறுத்திவிட்டன"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6cdaa22..ff3f02c 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"తెరవడానికి మళ్లీ నొక్కండి"</string>
<string name="tap_again" msgid="1315420114387908655">"మళ్లీ ట్యాప్ చేయండి"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"తెరవడానికి, పైకి స్వైప్ చేయండి"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"తెరవడానికి నొక్కండి"</string>
<string name="keyguard_retry" msgid="886802522584053523">"మళ్ళీ ప్రయత్నించడానికి పైకి స్వైప్ చేయండి"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్లాక్ చేయండి"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
@@ -959,7 +958,7 @@
<string name="tuner_right" msgid="8247571132790812149">"కుడి"</string>
<string name="tuner_menu" msgid="363690665924769420">"మెనూ"</string>
<string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> అనురవర్తనం"</string>
- <string name="notification_channel_alerts" msgid="3385787053375150046">"హెచ్చరికలు"</string>
+ <string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్లు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్షాట్లు"</string>
<string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ సందేశాలు"</string>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 1879edd..7eded1e 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"మైక్రోఫోన్ రికార్డింగ్ చేస్తోంది"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"కెమెరా రికార్డింగ్ చేస్తోంది"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేస్తున్నాయి"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేసింది"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"కెమెరా రికార్డింగ్ చేయడం ఆపివేసింది"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేశాయి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f2fce1e..13e88c5 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -353,7 +353,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ปิดตำแหน่ง"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"มี"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"พร้อมให้ใช้งาน"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ถูกบล็อก"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"อุปกรณ์สื่อ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
@@ -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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"แตะอีกครั้งเพื่อเปิด"</string>
<string name="tap_again" msgid="1315420114387908655">"แตะอีกครั้ง"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"เลื่อนขึ้นเพื่อเปิด"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"กดเพื่อเปิด"</string>
<string name="keyguard_retry" msgid="886802522584053523">"เลื่อนขึ้นเพื่อลองอีกครั้ง"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 0724821..458dc7e 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"ไมโครโฟนกำลังบันทึก"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"กล้องกำลังบันทึก"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"กล้องและไมโครโฟนกำลังบันทึก"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"ไมโครโฟนหยุดบันทึกแล้ว"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"กล้องหยุดบันทึกแล้ว"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"กล้องและไมโครโฟนหยุดบันทึกแล้ว"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3ef994e..261f568 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"I-tap ulit upang buksan"</string>
<string name="tap_again" msgid="1315420114387908655">"I-tap ulit"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Mag-swipe pataas para buksan"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pindutin para buksan"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Mag-swipe pataas para subukan ulit"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 8dcc22f..b45d62b 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Nagre-record ang Mikropono"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Nagre-record ang Camera"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Nagre-record ang Camera at Mikropono"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Huminto sa pag-record ang Mikropono"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Huminto sa pag-record ang Camera"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Huminto sa pag-record ang Camera at Mikropono"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d9afda18..a96c62d 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Açmak için tekrar dokunun"</string>
<string name="tap_again" msgid="1315420114387908655">"Tekrar dokunun"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmak için yukarı kaydırın"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmak için basın"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Tekrar denemek için yukarı kaydırın"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 49e76af..54f24c3 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon kaydediyor"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera kaydediyor"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera ve Mikrofon kaydediyor"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon kaydı durdu"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera kaydı durdu"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera ve Mikrofon kaydı durdu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 50a0f52..8637ad7 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>
@@ -458,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Торкніться знову, щоб відкрити"</string>
<string name="tap_again" msgid="1315420114387908655">"Натисніть знову"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведіть пальцем угору, щоб відкрити"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натисніть, щоб відкрити"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index 170b068..2ec6d9a 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Мікрофон записує"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Камера записує"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Камера й мікрофон записують"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Мікрофон припинив запис"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Камера припинила запис"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Камера й мікрофон припинили запис"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 62b09f2..4321c3e 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string>
<string name="tap_again" msgid="1315420114387908655">"دوبارہ تھپتھپائیں"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"کھولنے کے لیے اوپر سوائپ کريں"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"کھولنے کے لیے دبائیں"</string>
<string name="keyguard_retry" msgid="886802522584053523">"دوبارہ کوشش کرنے کے لیے اوپر سوائپ کريں"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
diff --git a/packages/SystemUI/res/values-ur/strings_tv.xml b/packages/SystemUI/res/values-ur/strings_tv.xml
index fbaa3f6..566b33f 100644
--- a/packages/SystemUI/res/values-ur/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"مائیکروفون ریکارڈ کر رہا ہے"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"کیمرا ریکارڈ کر رہا ہے"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"کیمرا اور مائیکروفون ریکارڈ کر رہا ہے"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"مائیکروفون نے ریکارڈ کرنا بند کر دیا"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"کیمرے نے ریکارڈ کرنا بند کر دیا"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"کیمرے اور مائیکروفون نے ریکارڈ کرنا بند کر دیا"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fae90c8..ee68d27 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ochish uchun yana bosing"</string>
<string name="tap_again" msgid="1315420114387908655">"Yana bosing"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ochish uchun tepaga suring"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ochish uchun bosing"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Qayta urinish uchun tepaga suring"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</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..c528165f 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Nhấn lại để mở"</string>
<string name="tap_again" msgid="1315420114387908655">"Nhấn lại"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Vuốt lên để mở"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nhấn để mở"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Vuốt lên để thử lại"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 3dfc8c1..0144884 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Micrô đang ghi"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Máy ảnh đang ghi"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Máy ảnh và micrô đang ghi"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Micrô đã dừng ghi"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Máy ảnh đã dừng ghi"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Máy ảnh và micrô đã dừng ghi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-w390dp/config.xml b/packages/SystemUI/res/values-w390dp/config.xml
new file mode 100644
index 0000000..222d848
--- /dev/null
+++ b/packages/SystemUI/res/values-w390dp/config.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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>
+ <bool name="config_showBatteryEstimateQSBH">true</bool>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a8b8285..4d7cdee 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次点按即可打开"</string>
<string name="tap_again" msgid="1315420114387908655">"请再点按一次"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑动即可打开"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按一下即可打开"</string>
<string name="keyguard_retry" msgid="886802522584053523">"向上滑动即可重试"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</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..ed914c9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麦克风正在录制"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相机正在录制"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相机和麦克风正在录制"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麦克风已停止录制"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相机已停止录制"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相机和麦克风已停止录制"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9e498f6..ff4dddc 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次輕按即可開啟"</string>
<string name="tap_again" msgid="1315420114387908655">"再次輕按"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
<string name="keyguard_retry" msgid="886802522584053523">"請向上滑動以再試一次"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</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..dfc34e5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麥克風正在錄音"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相機正在錄影"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相機和麥克風正在錄影及錄音"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麥克風已停止錄音"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相機已停止錄影"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相機和麥克風已停止錄影及錄音"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1b0fa10..88b35a6 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次輕觸即可開啟"</string>
<string name="tap_again" msgid="1315420114387908655">"再輕觸一次"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
<string name="keyguard_retry" msgid="886802522584053523">"向上滑動即可重試"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</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..869ac48 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"麥克風正在錄音"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"相機正在錄影"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"相機和麥克風正在錄影及錄音"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"麥克風已停止錄音"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"相機已停止錄影"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"相機和麥克風已停止錄影及錄音"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a14229a..0e0e893 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>
@@ -454,6 +452,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Thepha futhi ukuze uvule"</string>
<string name="tap_again" msgid="1315420114387908655">"Thepha futhi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swayiphela phezulu ukuze uvule"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Chofoza ukuze uvule"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swayiphela phezulu ukuze uzame futhi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index a9b7597..a3e5255 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -26,4 +26,10 @@
<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>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Imakrofoni iyarekhoda"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Ikhamera iyarekhoda"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Ikhamera nemakrofoni kuyarekhoda"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Imakrofoni iyekile ukurekhoda"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Ikhamera iyeke ukurekhoda"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Ikhemera nemakrofoni kuyekile ukurekhoda"</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index bf29cf4..5e85480 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -313,7 +313,8 @@
<!-- SystemUIFactory component -->
<string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
- <!-- SystemUI Services: The classes of the stuff to start. -->
+ <!-- SystemUI Services: The classes of base stuff to start by default for all
+ configurations. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
@@ -340,6 +341,12 @@
<item>com.android.systemui.wmshell.WMShell</item>
</string-array>
+ <!-- SystemUI Services: The classes of the additional stuff to start. Services here are
+ specified as an overlay to provide configuration-specific services that
+ supplement those listed in config_systemUIServiceComponents. -->
+ <string-array name="config_additionalSystemUIServiceComponents" translatable="false">
+ </string-array>
+
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
<dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
<dimen name="config_qsTileStrokeWidthInactive">-1dp</dimen>
@@ -542,6 +549,11 @@
<item>@*android:string/status_bar_headset</item>
</string-array>
+
+ <!-- Whether to show estimate in QS header. Default to false in case there's not enough
+ space -->
+ <bool name="config_showBatteryEstimateQSBH">false</bool>
+
<!-- A path similar to frameworks/base/core/res/res/values/config.xml
config_mainBuiltInDisplayCutout that describes a path larger than the exact path of a display
cutout. If present as well as config_enableDisplayCutoutProtection is set to true, then
@@ -666,4 +678,20 @@
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>
+
+ <!-- Whether idle mode should be enabled. When enabled, the lock screen will timeout to an idle
+ screen on inactivity. -->
+ <bool name="config_enableIdleMode">false</bool>
+
+ <!-- Timeout to idle mode duration in milliseconds. -->
+ <integer name="config_idleModeTimeout">10000</integer>
+
+ <!-- Tiemout to doze mode from idle in milliseconds. -->
+ <integer name="config_dozeModeTimeout">15000</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 22035f4..a12fd2b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -916,8 +916,8 @@
<dimen name="keyguard_affordance_height">48dp</dimen>
<dimen name="keyguard_affordance_width">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_height">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_width">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_height">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_width">48dp</dimen>
<dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
<dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
@@ -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>
@@ -1290,7 +1293,7 @@
<!-- Size of media cards in the QSPanel carousel -->
<dimen name="qs_media_padding">16dp</dimen>
<dimen name="qs_media_album_size_small">72dp</dimen>
- <dimen name="qs_media_album_size">92dp</dimen>
+ <dimen name="qs_media_album_size">84dp</dimen>
<dimen name="qs_media_album_radius">14dp</dimen>
<dimen name="qs_media_album_device_padding">26dp</dimen>
<dimen name="qs_media_info_margin">12dp</dimen>
@@ -1307,13 +1310,14 @@
<dimen name="qs_footer_horizontal_margin">22dp</dimen>
<dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
<dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
- <dimen name="qs_media_enabled_seekbar_vertical_padding">31dp</dimen>
- <dimen name="qs_media_disabled_seekbar_vertical_padding">32dp</dimen>
+ <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
+ <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
- <dimen name="qs_aa_media_rec_album_size_expanded">80dp</dimen>
+ <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
<dimen name="qs_aa_media_rec_album_margin">8dp</dimen>
+ <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
<dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
<!-- Window magnification -->
@@ -1462,7 +1466,7 @@
<dimen name="lockscreen_shade_notification_movement">24dp</dimen>
<!-- Maximum overshoot for the pulse expansion -->
- <dimen name="pulse_expansion_max_top_overshoot">16dp</dimen>
+ <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
@@ -1619,4 +1623,7 @@
<dimen name="settingslib_switch_track_height">24dp</dimen>
<!-- Radius of switch track -->
<dimen name="settingslib_switch_track_radius">31dp</dimen>
+
+ <!-- Height percentage of the parent container occupied by the communal view -->
+ <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
</resources>
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/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 91d5d79..d254742 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -764,6 +764,8 @@
<item name="android:windowBackground">@android:color/black</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:statusBarColor">@android:color/black</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
@@ -898,6 +900,8 @@
<style name="Wallet.Theme" parent="@android:style/Theme.DeviceDefault">
<item name="android:colorBackground">@android:color/system_neutral1_900</item>
<item name="android:itemBackground">@android:color/system_neutral1_800</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen. -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
</style>
<style name="Animation.InternetDialog" parent="@android:style/Animation.InputMethod">
@@ -938,4 +942,13 @@
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
+ <style name="TrimmedHorizontalProgressBar"
+ parent="android:Widget.Material.ProgressBar.Horizontal">
+ <item name="android:indeterminateDrawable">
+ @drawable/progress_indeterminate_horizontal_material_trimmed
+ </item>
+ <item name="android:minHeight">4dp</item>
+ <item name="android:maxHeight">4dp</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 9d706c5..0e284e6 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -93,7 +93,7 @@
android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_info_margin"
app:layout_constrainedWidth="true"
- android:layout_marginTop="@dimen/qs_media_info_spacing"
+ android:layout_marginTop="1dp"
app:layout_constraintTop_toBottomOf="@id/header_title"
app:layout_constraintStart_toStartOf="@id/header_title"
app:layout_constraintEnd_toEndOf="parent"
@@ -104,7 +104,8 @@
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
- app:layout_constraintTop_toBottomOf="@id/header_artist"
+ android:layout_marginTop="34dp"
+ app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
@@ -124,7 +125,6 @@
android:id="@+id/action0"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginTop="@dimen/qs_media_action_margin"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -139,7 +139,6 @@
android:id="@+id/action1"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginTop="@dimen/qs_media_action_margin"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -153,7 +152,6 @@
android:id="@+id/action2"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginTop="@dimen/qs_media_action_margin"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -167,7 +165,6 @@
android:id="@+id/action3"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginTop="@dimen/qs_media_action_margin"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -181,7 +178,6 @@
android:id="@+id/action4"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginTop="@dimen/qs_media_action_margin"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_action_margin"
diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
index d8e132c..8a3d5ca 100644
--- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
@@ -43,7 +43,7 @@
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -61,7 +61,7 @@
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -79,7 +79,7 @@
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
app:layout_constraintStart_toEndOf="@id/media_cover2_container"
@@ -95,7 +95,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -113,7 +113,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -131,7 +131,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+ android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"
app:layout_constraintBottom_toBottomOf="parent"
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/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 2407d21..23a365a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -68,6 +68,7 @@
public final boolean isNotInRecents;
public final Rect contentInsets;
public final ActivityManager.RunningTaskInfo taskInfo;
+ public final boolean allowEnterPip;
public final int rotationChange;
public final int windowType;
@@ -88,6 +89,7 @@
contentInsets = app.contentInsets;
activityType = app.windowConfiguration.getActivityType();
taskInfo = app.taskInfo;
+ allowEnterPip = app.allowEnterPip;
rotationChange = 0;
mStartLeash = app.startLeash;
@@ -214,6 +216,7 @@
activityType = ACTIVITY_TYPE_UNDEFINED;
}
taskInfo = change.getTaskInfo();
+ allowEnterPip = false; /* always false in shell-transition case */
mStartLeash = null;
rotationChange = change.getEndRotation() - change.getStartRotation();
windowType = INVALID_WINDOW_TYPE;
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..2519284 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;
@@ -130,12 +131,13 @@
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null) {
- pausingTask = change.getTaskInfo().token;
+ if (taskInfo == null) {
+ continue;
}
+ pausingTask = taskInfo.token;
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
- pipTask = change.getTaskInfo().token;
+ pipTask = taskInfo.token;
}
}
}
@@ -166,7 +168,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 +176,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..ad196ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -103,10 +103,10 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -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;
@@ -146,7 +149,7 @@
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_SPEW = false;
- private static final int LOW_BATTERY_THRESHOLD = 20;
+ private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
private static final String ACTION_FACE_UNLOCK_STARTED
= "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -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++) {
@@ -808,7 +834,18 @@
private void handleFingerprintLockoutReset() {
mFingerprintLockedOut = false;
mFingerprintLockedOutPermanent = false;
- updateFingerprintListeningState();
+
+ if (isUdfpsEnrolled()) {
+ // TODO(b/194825098): update the reset signal(s)
+ // A successful unlock will trigger a lockout reset, but there is no guarantee
+ // that the events will arrive in a particular order. Add a delay here in case
+ // an unlock is in progress. In this is a normal unlock the extra delay won't
+ // be noticeable.
+ mHandler.postDelayed(this::updateFingerprintListeningState,
+ FINGERPRINT_LOCKOUT_RESET_DELAY_MS);
+ } else {
+ updateFingerprintListeningState();
+ }
}
private void setFingerprintRunningState(int fingerprintRunningState) {
@@ -2042,6 +2079,15 @@
}
/**
+ * @return if udfps is available on this device. will return true even if the user hasn't
+ * enrolled udfps.
+ */
+ public boolean isUdfpsAvailable() {
+ return mAuthController.getUdfpsProps() != null
+ && !mAuthController.getUdfpsProps().isEmpty();
+ }
+
+ /**
* @return true if there's at least one face enrolled
*/
public boolean isFaceEnrolled() {
@@ -2372,8 +2418,10 @@
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
+ final boolean isBypassEnabled = mKeyguardBypassController != null
+ && mKeyguardBypassController.isBypassEnabled();
mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
- mFaceAuthenticationCallback, null /* handler */, userId);
+ mFaceAuthenticationCallback, null /* handler */, userId, isBypassEnabled);
}
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
@@ -3354,6 +3402,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 +3424,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/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index c1d448d..622419a8 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -17,15 +17,21 @@
package com.android.keyguard;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.PointF;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.NonNull;
+import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -33,16 +39,47 @@
/**
* A view positioned under the notification shade.
*/
-public class LockIconView extends ImageView implements Dumpable {
+public class LockIconView extends FrameLayout implements Dumpable {
@NonNull private final RectF mSensorRect;
@NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
private int mRadius;
+ private ImageView mLockIcon;
+ private ImageView mUnlockBgView;
+
+ private int mLockIconColor;
+
public LockIconView(Context context, AttributeSet attrs) {
super(context, attrs);
mSensorRect = new RectF();
}
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ mLockIcon = findViewById(R.id.lock_icon);
+ mUnlockBgView = findViewById(R.id.lock_icon_bg);
+ }
+
+ void updateColorAndBackgroundVisibility(boolean useBackground) {
+ if (useBackground) {
+ mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.textColorPrimary);
+ mUnlockBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
+ mUnlockBgView.setVisibility(View.VISIBLE);
+ } else {
+ mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
+ R.attr.wallpaperTextColorAccent);
+ mUnlockBgView.setVisibility(View.GONE);
+ }
+
+ mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor));
+ }
+
+ void setImageDrawable(Drawable drawable) {
+ mLockIcon.setImageDrawable(drawable);
+ }
+
void setCenterLocation(@NonNull PointF center, int radius) {
mLockIconCenter = center;
mRadius = radius;
@@ -56,9 +93,12 @@
setX(mSensorRect.left);
setY(mSensorRect.top);
- setLayoutParams(new FrameLayout.LayoutParams(
+
+ final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
(int) (mSensorRect.right - mSensorRect.left),
- (int) (mSensorRect.bottom - mSensorRect.top)));
+ (int) (mSensorRect.bottom - mSensorRect.top));
+ lp.gravity = Gravity.CENTER;
+ setLayoutParams(lp);
}
@Override
@@ -70,7 +110,6 @@
return mLockIconCenter.y - mRadius;
}
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8b974b4..4317e25 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -43,7 +43,6 @@
import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
@@ -72,7 +71,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)
@@ -94,8 +96,8 @@
@NonNull private final AnimatedVectorDrawable mLockToUnlockIcon;
@NonNull private final Drawable mLockIcon;
@NonNull private final Drawable mUnlockIcon;
- @NonNull private final CharSequence mUnlockedLabel;
- @NonNull private final CharSequence mLockedLabel;
+ @NonNull private CharSequence mUnlockedLabel;
+ @NonNull private CharSequence mLockedLabel;
@Nullable private final Vibrator mVibrator;
private boolean mIsDozing;
@@ -108,12 +110,10 @@
private boolean mUserUnlockedWithBiometric;
private Runnable mCancelDelayedUpdateVisibilityRunnable;
- private boolean mHasUdfps;
+ private boolean mUdfpsSupported;
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;
@@ -151,9 +151,8 @@
final Context context = view.getContext();
mUnlockIcon = mView.getContext().getResources().getDrawable(
- R.anim.lock_to_unlock,
+ R.drawable.ic_unlock,
mView.getContext().getTheme());
- ((AnimatedVectorDrawable) mUnlockIcon).start();
mLockIcon = mView.getContext().getResources().getDrawable(
R.anim.lock_to_unlock,
mView.getContext().getTheme());
@@ -176,7 +175,7 @@
protected void onViewAttached() {
// we check this here instead of onInit since the FingerprintManager + FaceManager may not
// have started up yet onInit
- mHasUdfps = mAuthController.getUdfpsSensorLocation() != null;
+ mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
updateConfiguration();
updateKeyguardShowing();
@@ -306,52 +305,39 @@
}
private void updateColors() {
- final int color = Utils.getColorAttrDefaultColor(mView.getContext(),
- R.attr.wallpaperTextColorAccent);
- mFpToUnlockIcon.setTint(color);
- mLockToUnlockIcon.setTint(color);
- mLockIcon.setTint(color);
- mUnlockIcon.setTint(color);
+ mView.updateColorAndBackgroundVisibility(mUdfpsSupported);
}
private void updateConfiguration() {
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);
+
+ mUnlockedLabel = mView.getContext().getResources().getString(
+ R.string.accessibility_unlock_button);
+ mLockedLabel = mView.getContext()
+ .getResources().getString(R.string.accessibility_lock_icon);
+
updateLockIconLocation();
}
private void updateLockIconLocation() {
- if (mHasUdfps) {
+ if (mUdfpsSupported) {
FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
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);
@@ -480,6 +466,7 @@
@Override
public void onConfigChanged(Configuration newConfig) {
updateConfiguration();
+ updateColors();
}
};
@@ -573,7 +560,7 @@
}
private boolean isClickable() {
- return mUdfpsEnrolled || mShowUnlockIcon;
+ return mUdfpsSupported || mShowUnlockIcon;
}
/**
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/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index a672523..fc14b6a 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -18,6 +18,7 @@
import com.android.keyguard.CarrierText;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import dagger.Module;
@@ -31,4 +32,11 @@
static CarrierText getCarrierText(KeyguardStatusBarView view) {
return view.findViewById(R.id.keyguard_carrier_text);
}
+
+ /** */
+ @Provides
+ @KeyguardStatusBarViewScope
+ static BatteryMeterView getBatteryMeterView(KeyguardStatusBarView view) {
+ return view.findViewById(R.id.battery);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 2652638..48c5e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -47,6 +47,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -73,7 +74,6 @@
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -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;
@@ -358,6 +359,7 @@
@Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy;
@Inject Lazy<EdgeBackGestureHandler.Factory> mEdgeBackGestureHandlerFactoryLazy;
@Inject Lazy<UiEventLogger> mUiEventLogger;
+ @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
@Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
@Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
@@ -575,6 +577,7 @@
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/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 1d355f2..b5b6b13 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -93,7 +93,7 @@
SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
if (notFirstLogin != 0) {
mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
- mUserTracker, mUiEventLogger, userId);
+ mUiEventLogger, userId);
mNewSessionDialog.show();
} else {
mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
@@ -126,7 +126,6 @@
ResetSessionDialog(Context context,
UserSwitcherController userSwitcherController,
- UserTracker userTracker,
UiEventLogger uiEventLogger,
int userId) {
super(context);
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/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index e9c5653..f653088 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -797,8 +797,8 @@
}
static boolean shouldDrawCutout(Context context) {
- return context.getResources().getBoolean(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
+ return DisplayCutout.getFillBuiltInDisplayCutout(
+ context.getResources(), context.getDisplay().getUniqueId());
}
private void updateLayoutParams() {
@@ -1085,7 +1085,8 @@
int dw = flipped ? lh : lw;
int dh = flipped ? lw : lh;
- Path path = DisplayCutout.pathFromResources(getResources(), dw, dh);
+ Path path = DisplayCutout.pathFromResources(
+ getResources(), getDisplay().getUniqueId(), dw, dh);
if (path != null) {
mBoundingPath.set(path);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 865ca40..4fd2701 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,6 +42,8 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
/**
* Application class for SystemUI.
@@ -159,8 +161,17 @@
*/
public void startServicesIfNeeded() {
- String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
- startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
+ final String[] names = SystemUIFactory.getInstance()
+ .getSystemUIServiceComponents(getResources());
+ final String[] additionalNames = SystemUIFactory.getInstance()
+ .getAdditionalSystemUIServiceComponents(getResources());
+
+ final ArrayList<String> serviceComponents = new ArrayList<>();
+ Collections.addAll(serviceComponents, names);
+ Collections.addAll(serviceComponents, additionalNames);
+
+ startServicesIfNeeded(/* metricsPrefix= */ "StartServices",
+ serviceComponents.toArray(new String[serviceComponents.size()]));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index a28223d..d31301a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -187,6 +187,13 @@
}
/**
+ * Returns the list of additional system UI components that should be started.
+ */
+ public String[] getAdditionalSystemUIServiceComponents(Resources resources) {
+ return resources.getStringArray(R.array.config_additionalSystemUIServiceComponents);
+ }
+
+ /**
* Returns the list of system UI components that should be started per user.
*/
public String[] getSystemUIServiceComponentsPerUser(Resources resources) {
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/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
rename to packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 6fc2e41..88c09dc 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.battery;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
@@ -50,6 +50,9 @@
import androidx.annotation.StyleRes;
import com.android.settingslib.graph.ThemedBatteryDrawable;
+import com.android.systemui.Dependency;
+import com.android.systemui.DualToneHandler;
+import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -196,6 +199,7 @@
* @param mode desired mode (none, on, off)
*/
public void setPercentShowMode(@BatteryPercentMode int mode) {
+ if (mode == mShowPercentMode) return;
mShowPercentMode = mode;
updateShowPercent();
}
@@ -331,7 +335,7 @@
if (mBatteryPercentView == null) {
return;
}
- if (estimate != null) {
+ if (estimate != null && mShowPercentMode == MODE_ESTIMATE) {
mBatteryPercentView.setText(estimate);
setContentDescription(getContext().getString(
R.string.accessibility_battery_level_with_estimate,
@@ -486,6 +490,7 @@
pw.println(" mTextColor: #" + Integer.toHexString(mTextColor));
pw.println(" mBatteryStateUnknown: " + mBatteryStateUnknown);
pw.println(" mLevel: " + mLevel);
+ pw.println(" mMode: " + mShowPercentMode);
}
private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
new file mode 100644
index 0000000..27a6b3c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.battery;
+
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+/** Controller for {@link BatteryMeterView}. **/
+public class BatteryMeterViewController extends ViewController<BatteryMeterView> {
+
+ @Inject
+ public BatteryMeterViewController(BatteryMeterView view) {
+ super(view);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ }
+
+ @Override
+ protected void onViewDetached() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index 205054d..98ad875 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -93,6 +93,8 @@
@Nullable private ModalityListener mModalityListener;
@Nullable private FingerprintSensorPropertiesInternal mFingerprintSensorProps;
@Nullable private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter;
+ @Nullable @VisibleForTesting UdfpsIconController mUdfpsIconController;
+
public AuthBiometricFaceToFingerprintView(Context context) {
super(context);
@@ -107,6 +109,12 @@
super(context, attrs, injector);
}
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mUdfpsIconController = new UdfpsIconController(mContext, mIconView, mIndicatorView);
+ }
+
@Modality
int getActiveSensorType() {
return mActiveSensorType;
@@ -168,35 +176,26 @@
}
@Override
- @NonNull
- protected IconController getIconController() {
- if (mActiveSensorType == TYPE_FINGERPRINT) {
- if (!(mIconController instanceof UdfpsIconController)) {
- mIconController = createUdfpsIconController();
- }
- return mIconController;
- }
- return super.getIconController();
- }
-
- @NonNull
- protected IconController createUdfpsIconController() {
- return new UdfpsIconController(getContext(), mIconView, mIndicatorView);
- }
-
- @Override
public void updateState(@BiometricState int newState) {
- if (mState == STATE_HELP || mState == STATE_ERROR) {
- @Modality final int currentType = mActiveSensorType;
- mActiveSensorType = TYPE_FINGERPRINT;
+ if (mActiveSensorType == TYPE_FACE) {
+ if (newState == STATE_HELP || newState == STATE_ERROR) {
+ mActiveSensorType = TYPE_FINGERPRINT;
- setRequireConfirmation(false);
- mConfirmButton.setEnabled(false);
- mConfirmButton.setVisibility(View.GONE);
+ setRequireConfirmation(false);
+ mConfirmButton.setEnabled(false);
+ mConfirmButton.setVisibility(View.GONE);
- if (mModalityListener != null && currentType != mActiveSensorType) {
- mModalityListener.onModalitySwitched(currentType, mActiveSensorType);
+ if (mModalityListener != null) {
+ mModalityListener.onModalitySwitched(TYPE_FACE, mActiveSensorType);
+ }
+
+ // Deactivate the face icon controller so it stops drawing to the view
+ mFaceIconController.deactivate();
+ // Then, activate this icon controller. We need to start in the "error" state
+ mUdfpsIconController.updateState(mState, newState);
}
+ } else { // Fingerprint
+ mUdfpsIconController.updateState(mState, newState);
}
super.updateState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index e8da7c5..c32c1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -49,6 +49,7 @@
protected Handler mHandler;
protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark
protected @BiometricState int mState;
+ protected boolean mDeactivated;
protected IconController(Context context, ImageView iconView, TextView textView) {
mContext = context;
@@ -67,6 +68,11 @@
}
protected void animateIcon(int iconRes, boolean repeat) {
+ Log.d(TAG, "animateIcon, state: " + mState + ", deactivated: " + mDeactivated);
+ if (mDeactivated) {
+ return;
+ }
+
final AnimatedVectorDrawable icon =
(AnimatedVectorDrawable) mContext.getDrawable(iconRes);
mIconView.setImageDrawable(icon);
@@ -92,12 +98,26 @@
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
+ Log.d(TAG, "onAnimationEnd, mState: " + mState + ", deactivated: " + mDeactivated);
+ if (mDeactivated) {
+ return;
+ }
+
if (mState == STATE_AUTHENTICATING || mState == STATE_HELP) {
pulseInNextDirection();
}
}
+ protected void deactivate() {
+ mDeactivated = true;
+ }
+
protected void updateState(int lastState, int newState) {
+ if (mDeactivated) {
+ Log.w(TAG, "Ignoring updateState when deactivated: " + newState);
+ return;
+ }
+
final boolean lastStateIsErrorIcon =
lastState == STATE_ERROR || lastState == STATE_HELP;
@@ -142,7 +162,7 @@
}
}
- protected IconController mIconController;
+ @Nullable @VisibleForTesting IconController mFaceIconController;
public AuthBiometricFaceView(Context context) {
this(context, null);
@@ -158,6 +178,12 @@
}
@Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mFaceIconController = new IconController(mContext, mIconView, mIndicatorView);
+ }
+
+ @Override
protected int getDelayAfterAuthenticatedDurationMs() {
return HIDE_DELAY_MS;
}
@@ -187,17 +213,9 @@
return true;
}
- @NonNull
- protected IconController getIconController() {
- if (mIconController == null) {
- mIconController = new IconController(mContext, mIconView, mIndicatorView);
- }
- return mIconController;
- }
-
@Override
public void updateState(@BiometricState int newState) {
- getIconController().updateState(mState, newState);
+ mFaceIconController.updateState(mState, newState);
if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
(newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
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..69f9004 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;
@@ -71,6 +72,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
@@ -122,6 +124,7 @@
@NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Nullable private final UdfpsHbmProvider mHbmProvider;
@NonNull private final KeyguardBypassController mKeyguardBypassController;
+ @NonNull private final ConfigurationController mConfigurationController;
@VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@@ -519,7 +522,10 @@
@NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
@NonNull Optional<UdfpsHbmProvider> hbmProvider,
@NonNull KeyguardStateController keyguardStateController,
- @NonNull KeyguardBypassController keyguardBypassController) {
+ @NonNull KeyguardBypassController keyguardBypassController,
+ @NonNull DisplayManager displayManager,
+ @Main Handler mainHandler,
+ @NonNull ConfigurationController configurationController) {
mContext = context;
mExecution = execution;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -545,11 +551,16 @@
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;
+ mConfigurationController = configurationController;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -662,7 +673,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 +684,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
@@ -767,6 +780,7 @@
mDumpManager,
mKeyguardViewMediator,
mLockscreenShadeTransitionController,
+ mConfigurationController,
this
);
case IUdfpsOverlayController.REASON_AUTH_BP:
@@ -874,11 +888,16 @@
private void onFingerDown(int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
- mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
if (mView == null) {
Log.w(TAG, "Null view in onFingerDown");
return;
}
+
+ if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+ && !mStatusBarStateController.isDozing()) {
+ mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
+ }
+
if (!mOnFingerDown) {
playStartHaptic();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index eb02aa0..d122610 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -22,7 +22,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -51,17 +50,14 @@
private UdfpsDrawable mFingerprintDrawable; // placeholder
private LottieAnimationView mAodFp;
private LottieAnimationView mLockScreenFp;
- private int mUdfpsBouncerColor;
- private int mWallpaperTextColor;
private int mStatusBarState;
// used when highlighting fp icon:
private int mTextColorPrimary;
private ImageView mBgProtection;
boolean mUdfpsRequested;
- int mUdfpsRequestedColor;
- private AnimatorSet mAnimatorSet;
+ private AnimatorSet mBackgroundInAnimator = new AnimatorSet();
private int mAlpha; // 0-255
// AOD anti-burn-in offsets
@@ -89,20 +85,15 @@
super.onFinishInflate();
mAodFp = findViewById(R.id.udfps_aod_fp);
mLockScreenFp = findViewById(R.id.udfps_lockscreen_fp);
-
mBgProtection = findViewById(R.id.udfps_keyguard_fp_bg);
- mWallpaperTextColor = Utils.getColorAttrDefaultColor(mContext,
- R.attr.wallpaperTextColorAccent);
- mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
- android.R.attr.textColorPrimary);
+ updateColor();
- // requires call to invalidate to update the color (see #updateColor)
+ // requires call to invalidate to update the color
mLockScreenFp.addValueCallback(
new KeyPath("**"), LottieProperty.COLOR_FILTER,
- frameInfo -> new PorterDuffColorFilter(getColor(), PorterDuff.Mode.SRC_ATOP)
+ frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
);
- mUdfpsRequested = false;
mHintAnimator = ObjectAnimator.ofFloat(mLockScreenFp, "progress", 1f, 0f, 1f);
mHintAnimator.setDuration(4000);
@@ -148,13 +139,7 @@
}
void requestUdfps(boolean request, int color) {
- if (request) {
- mUdfpsRequestedColor = color;
- } else {
- mUdfpsRequestedColor = -1;
- }
mUdfpsRequested = request;
- updateColor();
}
void setStatusBarState(int statusBarState) {
@@ -162,31 +147,10 @@
}
void updateColor() {
- mWallpaperTextColor = Utils.getColorAttrDefaultColor(mContext,
- R.attr.wallpaperTextColorAccent);
mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
android.R.attr.textColorPrimary);
- mLockScreenFp.invalidate();
- mBgProtection.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
- }
-
- private boolean showingUdfpsBouncer() {
- return mBgProtection.getVisibility() == View.VISIBLE;
- }
-
-
- private int getColor() {
- if (isUdfpsColorRequested()) {
- return mUdfpsRequestedColor;
- } else if (showingUdfpsBouncer()) {
- return mUdfpsBouncerColor;
- } else {
- return mWallpaperTextColor;
- }
- }
-
- private boolean isUdfpsColorRequested() {
- return mUdfpsRequested && mUdfpsRequestedColor != -1;
+ mBgProtection.setImageDrawable(getContext().getDrawable(R.drawable.fingerprint_bg));
+ mLockScreenFp.invalidate(); // updated with a valueCallback
}
/**
@@ -200,7 +164,13 @@
@Override
protected int updateAlpha() {
int alpha = super.updateAlpha();
- mLockScreenFp.setImageAlpha(alpha);
+ mLockScreenFp.setAlpha(alpha / 255f);
+ if (mInterpolatedDarkAmount != 0f) {
+ mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
+ } else {
+ mBgProtection.setAlpha(alpha / 255f);
+ }
+
return alpha;
}
@@ -215,6 +185,7 @@
void onDozeAmountChanged(float linear, float eased) {
mHintAnimator.cancel();
mInterpolatedDarkAmount = eased;
+ updateAlpha();
updateBurnInOffsets();
}
@@ -228,52 +199,21 @@
/**
* Animates in the bg protection circle behind the fp icon to highlight the icon.
*/
- void animateUdfpsBouncer(Runnable onEndAnimation) {
- if (showingUdfpsBouncer() && mBgProtection.getAlpha() == 1f) {
- // already fully highlighted, don't re-animate
+ void animateInUdfpsBouncer(Runnable onEndAnimation) {
+ if (mBackgroundInAnimator.isRunning()) {
+ // already animating in
return;
}
- if (mAnimatorSet != null) {
- mAnimatorSet.cancel();
- }
-
- mAnimatorSet = new AnimatorSet();
- mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mAnimatorSet.setDuration(500);
- mAnimatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mBgProtection.setVisibility(View.VISIBLE);
- }
- });
-
- ValueAnimator fpIconColorAnim;
- if (isShadeLocked()) {
- // set color and fade in since we weren't showing before
- mUdfpsBouncerColor = mTextColorPrimary;
- fpIconColorAnim = ValueAnimator.ofInt(0, 255);
- fpIconColorAnim.addUpdateListener(valueAnimator ->
- mLockScreenFp.setImageAlpha((int) valueAnimator.getAnimatedValue()));
- } else {
- // update icon color
- fpIconColorAnim = new ValueAnimator();
- fpIconColorAnim.setIntValues(
- isUdfpsColorRequested() ? mUdfpsRequestedColor : mWallpaperTextColor,
- mTextColorPrimary);
- fpIconColorAnim.setEvaluator(ArgbEvaluator.getInstance());
- fpIconColorAnim.addUpdateListener(valueAnimator -> {
- mUdfpsBouncerColor = (int) valueAnimator.getAnimatedValue();
- updateColor();
- });
- }
-
- mAnimatorSet.playTogether(
+ // fade in and scale up
+ mBackgroundInAnimator = new AnimatorSet();
+ mBackgroundInAnimator.playTogether(
ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 0f, 1f),
ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f),
- ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f),
- fpIconColorAnim);
- mAnimatorSet.addListener(new AnimatorListenerAdapter() {
+ ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f));
+ mBackgroundInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mBackgroundInAnimator.setDuration(500);
+ mBackgroundInAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (onEndAnimation != null) {
@@ -281,66 +221,7 @@
}
}
});
- mAnimatorSet.start();
- }
-
- /**
- * Animates out the bg protection circle behind the fp icon to unhighlight the icon.
- */
- void animateAwayUdfpsBouncer(@Nullable Runnable onEndAnimation) {
- if (!showingUdfpsBouncer()) {
- // already hidden
- return;
- }
-
- if (mAnimatorSet != null) {
- mAnimatorSet.cancel();
- }
-
- ValueAnimator fpIconColorAnim;
- if (isShadeLocked()) {
- // fade out
- mUdfpsBouncerColor = mTextColorPrimary;
- fpIconColorAnim = ValueAnimator.ofInt(255, 0);
- fpIconColorAnim.addUpdateListener(valueAnimator ->
- mLockScreenFp.setImageAlpha((int) valueAnimator.getAnimatedValue()));
- } else {
- // update icon color
- fpIconColorAnim = new ValueAnimator();
- fpIconColorAnim.setIntValues(
- mTextColorPrimary,
- isUdfpsColorRequested() ? mUdfpsRequestedColor : mWallpaperTextColor);
- fpIconColorAnim.setEvaluator(ArgbEvaluator.getInstance());
- fpIconColorAnim.addUpdateListener(valueAnimator -> {
- mUdfpsBouncerColor = (int) valueAnimator.getAnimatedValue();
- updateColor();
- });
- }
-
- mAnimatorSet = new AnimatorSet();
- mAnimatorSet.playTogether(
- ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 1f, 0f),
- ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 1f, 0f),
- ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 1f, 0f),
- fpIconColorAnim);
- mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mAnimatorSet.setDuration(500);
-
- mAnimatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBgProtection.setVisibility(View.GONE);
- if (onEndAnimation != null) {
- onEndAnimation.run();
- }
- }
- });
-
- mAnimatorSet.start();
- }
-
- boolean isAnimating() {
- return mAnimatorSet != null && mAnimatorSet.isRunning();
+ mBackgroundInAnimator.start();
}
private boolean isShadeLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index bed3fd1..102dc41 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -19,6 +19,7 @@
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.annotation.NonNull;
+import android.content.res.Configuration;
import android.hardware.biometrics.BiometricSourceType;
import android.util.MathUtils;
import android.view.MotionEvent;
@@ -36,6 +37,7 @@
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
@@ -58,6 +60,7 @@
@NonNull private final DelayableExecutor mExecutor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
@NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
+ @NonNull private final ConfigurationController mConfigurationController;
@NonNull private final UdfpsController mUdfpsController;
@Nullable private Runnable mCancelDelayedHintRunnable;
@@ -88,6 +91,7 @@
@NonNull DumpManager dumpManager,
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull LockscreenShadeTransitionController transitionController,
+ @NonNull ConfigurationController configurationController,
@NonNull UdfpsController udfpsController) {
super(view, statusBarStateController, statusBarOptional, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -95,6 +99,7 @@
mExecutor = mainDelayableExecutor;
mKeyguardViewMediator = keyguardViewMediator;
mLockScreenShadeTransitionController = transitionController;
+ mConfigurationController = configurationController;
mUdfpsController = udfpsController;
}
@@ -121,6 +126,7 @@
mQsExpanded = mKeyguardViewManager.isQsExpanded();
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
+ mConfigurationController.addCallback(mConfigurationListener);
updateAlpha();
updatePauseAuth();
@@ -137,6 +143,7 @@
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
+ mConfigurationController.removeCallback(mConfigurationListener);
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
@@ -159,7 +166,6 @@
pw.println("mAlpha=" + mView.getAlpha());
pw.println("mUdfpsRequested=" + mUdfpsRequested);
pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
- pw.println("mView.mUdfpsRequestedColor=" + mView.mUdfpsRequestedColor);
}
/**
@@ -174,12 +180,17 @@
mShowingUdfpsBouncer = show;
updatePauseAuth();
if (mShowingUdfpsBouncer) {
- mView.animateUdfpsBouncer(() ->
- mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true));
+ if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
+ mView.animateInUdfpsBouncer(null);
+ }
+
+ if (mKeyguardViewManager.isOccluded()) {
+ mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
+ }
+
mView.announceForAccessibility(mView.getContext().getString(
R.string.accessibility_fingerprint_bouncer));
} else {
- mView.animateAwayUdfpsBouncer(null);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
}
return true;
@@ -367,7 +378,7 @@
@Override
public boolean isAnimating() {
- return mView.isAnimating();
+ return false;
}
@Override
@@ -378,6 +389,9 @@
@Override
public boolean onTouch(MotionEvent event) {
+ if (mTransitionToFullShadeProgress != 0) {
+ return false;
+ }
return mUdfpsController.onTouch(event);
}
@@ -405,4 +419,27 @@
pw.println(getTag());
}
};
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onUiModeChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mView.updateColor();
+ }
+ };
}
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..b81055d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -0,0 +1,187 @@
+/*
+ * 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.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;
+ }
+
+ @Override
+ public void init() {
+ super.init();
+
+ setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+ setState(STATE_DOZING, mStatusBarStateController.isDozing());
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ 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();
+ }
+}
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..5f75d86
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.idle.dagger.IdleViewComponent;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module providing Communal-related functionality.
+ */
+@Module(subcomponents = {
+ CommunalViewComponent.class,
+ IdleViewComponent.class,
+})
+public interface CommunalModule {
+ String IDLE_VIEW = "idle_view";
+
+ /** */
+ @Provides
+ @Named(IDLE_VIEW)
+ static View provideIdleView(Context context) {
+ FrameLayout view = new FrameLayout(context);
+ return view;
+ }
+}
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/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 239a77e..9cb9a36 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -39,6 +39,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
@@ -80,6 +81,7 @@
*/
@Module(includes = {
MediaModule.class,
+ PowerModule.class,
QSModule.class
})
public abstract class SystemUIDefaultModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 556f956..3d90ede 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -31,23 +31,23 @@
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;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -97,12 +97,12 @@
AppOpsModule.class,
AssistModule.class,
ClockModule.class,
+ CommunalModule.class,
ControlsModule.class,
DemoModeModule.class,
FalsingModule.class,
LogModule.class,
PeopleHubModule.class,
- PowerModule.class,
PluginModule.class,
ScreenshotModule.class,
SensorModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
index 6fbf81c..1fec7a6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
@@ -25,7 +25,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.wrapper.BuildInfo;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
rename to packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index 5a42458..5882179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.flags;
import android.content.Context;
import android.util.FeatureFlagUtils;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlagReader;
import javax.inject.Inject;
@@ -49,15 +48,11 @@
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);
}
+ /** */
public boolean useNewLockscreenAnimations() {
return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java
new file mode 100644
index 0000000..7d79279
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java
@@ -0,0 +1,42 @@
+/*
+ * 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.idle;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * {@link IdleHostView} houses a surface to be displayed when the device idle.
+ */
+public class IdleHostView extends FrameLayout {
+ public IdleHostView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public IdleHostView(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public IdleHostView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
new file mode 100644
index 0000000..ed177df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
@@ -0,0 +1,336 @@
+/*
+ * 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.idle;
+
+import static com.android.systemui.communal.dagger.CommunalModule.IDLE_VIEW;
+
+import android.annotation.IntDef;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.service.dreams.Sandman;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+/**
+ * {@link IdleHostViewController} processes signals to control the lifecycle of the idle screen.
+ */
+public class IdleHostViewController extends ViewController<IdleHostView> {
+ private static final String INPUT_MONITOR_IDENTIFIER = "IdleHostViewController";
+ private static final String TAG = "IdleHostViewController";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @IntDef({STATE_IDLE_MODE_ENABLED, STATE_DOZING, STATE_KEYGUARD_SHOWING, STATE_IDLING})
+ public @interface State {}
+
+ // Set at construction to indicate idle mode is available.
+ private static final int STATE_IDLE_MODE_ENABLED = 1 << 0;
+
+ // Set when the device has entered a system level dream.
+ private static final int STATE_DOZING = 1 << 1;
+
+ // Set when the keyguard is showing.
+ private static final int STATE_KEYGUARD_SHOWING = 1 << 2;
+
+ // Set when input monitoring has established the device is now idling.
+ private static final int STATE_IDLING = 1 << 3;
+
+ // The state the controller must be in to start recognizing idleness (lack of input
+ // interaction).
+ private static final int CONDITIONS_IDLE_MONITORING =
+ STATE_IDLE_MODE_ENABLED | STATE_KEYGUARD_SHOWING;
+
+ // The state the controller must be in before entering idle mode.
+ private static final int CONDITIONS_IDLING = CONDITIONS_IDLE_MONITORING | STATE_IDLING;
+
+ // The aggregate current state.
+ private int mState;
+ private boolean mIdleModeActive;
+
+ private final Context mContext;
+
+ // Timeout to idle in milliseconds.
+ private final int mIdleTimeout;
+ private final int mDozeTimeout;
+
+ // Factory for generating input listeners.
+ private final InputMonitorFactory mInputMonitorFactory;
+
+ // Delayable executor.
+ private final DelayableExecutor mDelayableExecutor;
+
+ private final BroadcastDispatcher mBroadcastDispatcher;
+
+ private final PowerManager mPowerManager;
+
+ // Runnable for canceling enabling idle.
+ private Runnable mCancelEnableIdling;
+
+ // Keyguard state controller for monitoring keyguard show state.
+ private final KeyguardStateController mKeyguardStateController;
+
+ // Status bar state controller for monitoring when the device is dozing.
+ private final StatusBarStateController mStatusBarStateController;
+
+ // Looper to use for monitoring input.
+ private final Looper mLooper;
+
+ // Choreographer to use for monitoring input.
+ private final Choreographer mChoreographer;
+
+ // Monitor for tracking touches for activity.
+ private InputMonitorCompat mInputMonitor;
+
+ // Delayed callback for enabling idle mode.
+ private final Runnable mEnableIdlingCallback = () -> {
+ if (DEBUG) {
+ Log.d(TAG, "enabling idle");
+ }
+ setState(STATE_IDLING, true);
+ };
+
+ // Delayed callback for enabling doze mode from idle.
+ private Runnable mIdleModeToDozeCallback = new Runnable() {
+ @Override
+ public void run() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Start dozing from timeout");
+ }
+ mPowerManager.goToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0);
+ }
+ };
+
+ private Runnable mCancelIdleModeToDoze;
+
+ private final KeyguardStateController.Callback mKeyguardCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+ }
+ };
+
+ private final StatusBarStateController.StateListener mStatusBarCallback =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setState(STATE_DOZING, isDozing);
+ }
+ };
+
+ private final BroadcastReceiver mDreamEndedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+ setState(STATE_IDLING, false);
+ }
+ }
+ };
+
+ final Provider<View> mIdleViewProvider;
+
+ @Inject
+ protected IdleHostViewController(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PowerManager powerManager,
+ IdleHostView view, InputMonitorFactory factory,
+ @Main DelayableExecutor delayableExecutor,
+ @Main Resources resources,
+ @Main Looper looper,
+ @Named(IDLE_VIEW) Provider<View> idleViewProvider,
+ Choreographer choreographer,
+ KeyguardStateController keyguardStateController,
+ StatusBarStateController statusBarStateController) {
+ super(view);
+ mContext = context;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mPowerManager = powerManager;
+ mIdleViewProvider = idleViewProvider;
+ mKeyguardStateController = keyguardStateController;
+ mStatusBarStateController = statusBarStateController;
+ mLooper = looper;
+ mChoreographer = choreographer;
+
+ mState = STATE_KEYGUARD_SHOWING;
+
+ final boolean enabled = resources.getBoolean(R.bool.config_enableIdleMode);
+ if (enabled) {
+ mState |= STATE_IDLE_MODE_ENABLED;
+ }
+
+ setState(mState, true);
+
+ mIdleTimeout = resources.getInteger(R.integer.config_idleModeTimeout);
+ mDozeTimeout = resources.getInteger(R.integer.config_dozeModeTimeout);
+ mInputMonitorFactory = factory;
+ mDelayableExecutor = delayableExecutor;
+
+ if (DEBUG) {
+ Log.d(TAG, "initial state:" + mState + " enabled:" + enabled
+ + " timeout:" + mIdleTimeout);
+ }
+ }
+
+ @Override
+ public void init() {
+ super.init();
+
+ setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+ setState(STATE_DOZING, mStatusBarStateController.isDozing());
+ }
+
+ private void setState(@State int state, boolean active) {
+ final int oldState = mState;
+
+ if (active) {
+ mState |= state;
+ } else {
+ mState &= ~state;
+ }
+
+ // If we have entered doze or no longer match the preconditions for idling, remove idling.
+ if ((mState & STATE_DOZING) == STATE_DOZING
+ || (mState & CONDITIONS_IDLE_MONITORING) != CONDITIONS_IDLE_MONITORING) {
+ mState &= ~STATE_IDLING;
+ }
+
+ if (oldState == mState) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "state changed from " + oldState + " to " + mState);
+ }
+
+ enableIdleMonitoring(mState == CONDITIONS_IDLE_MONITORING);
+ enableIdleMode(mState == CONDITIONS_IDLING);
+ }
+
+ private void enableIdleMonitoring(boolean enable) {
+ if (enable && mInputMonitor == null) {
+ if (DEBUG) {
+ Log.d(TAG, "enable idle monitoring");
+ }
+ // Set initial timeout to idle.
+ mCancelEnableIdling = mDelayableExecutor.executeDelayed(mEnableIdlingCallback,
+ mIdleTimeout);
+
+ // Monitor - any input should reset timer
+ mInputMonitor = mInputMonitorFactory.getInputMonitor(INPUT_MONITOR_IDENTIFIER);
+ mInputMonitor.getInputReceiver(mLooper, mChoreographer,
+ v -> {
+ if (DEBUG) {
+ Log.d(TAG, "touch detected, reseting timeout");
+ }
+ // When input is received, reset timeout.
+ if (mCancelEnableIdling != null) {
+ mCancelEnableIdling.run();
+ mCancelEnableIdling = null;
+ }
+ mCancelEnableIdling = mDelayableExecutor.executeDelayed(
+ mEnableIdlingCallback, mIdleTimeout);
+ });
+ } else if (!enable && mInputMonitor != null) {
+ if (DEBUG) {
+ Log.d(TAG, "disable idle monitoring");
+ }
+ // Clean up idle callback and touch monitoring.
+ if (mCancelEnableIdling != null) {
+ mCancelEnableIdling.run();
+ mCancelEnableIdling = null;
+ }
+
+ mInputMonitor.dispose();
+ mInputMonitor = null;
+ }
+ }
+
+ private void enableIdleMode(boolean enable) {
+ if (mIdleModeActive == enable) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "enable idle mode:" + enable);
+ }
+
+ mIdleModeActive = enable;
+
+ if (mIdleModeActive) {
+ mCancelIdleModeToDoze = mDelayableExecutor.executeDelayed(mIdleModeToDozeCallback,
+ mDozeTimeout);
+
+ // Track when the dream ends to cancel any timeouts.
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ mBroadcastDispatcher.registerReceiver(mDreamEndedReceiver, filter);
+
+ // Start dream.
+ Sandman.startDreamByUserRequest(mContext);
+ } else {
+ // Stop tracking dream end.
+ mBroadcastDispatcher.unregisterReceiver(mDreamEndedReceiver);
+
+ // Remove timeout.
+ if (mCancelIdleModeToDoze != null) {
+ mCancelIdleModeToDoze.run();
+ mCancelIdleModeToDoze = null;
+ }
+ }
+ }
+
+ @Override
+ protected void onViewAttached() {
+ if (DEBUG) {
+ Log.d(TAG, "onViewAttached");
+ }
+
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ mStatusBarStateController.addCallback(mStatusBarCallback);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ mStatusBarStateController.removeCallback(mStatusBarCallback);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java b/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java
new file mode 100644
index 0000000..be0a378
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java
@@ -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.idle;
+
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import javax.inject.Inject;
+
+/**
+ * {@link InputMonitorFactory} generates instances of {@link InputMonitorCompat}.
+ */
+public class InputMonitorFactory {
+ private final int mDisplayId;
+
+ @Inject
+ public InputMonitorFactory(@DisplayId int displayId) {
+ mDisplayId = displayId;
+ }
+
+ /**
+ * Generates a new {@link InputMonitorCompat}.
+ *
+ * @param identifier Identifier to generate monitor with.
+ * @return A {@link InputMonitorCompat} instance.
+ */
+ public InputMonitorCompat getInputMonitor(String identifier) {
+ return new InputMonitorCompat(identifier, mDisplayId);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.java b/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.java
new file mode 100644
index 0000000..9754b1f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.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.idle.dagger;
+
+import com.android.systemui.idle.IdleHostView;
+import com.android.systemui.idle.IdleHostViewController;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for working with {@link IdleHostView}.
+ */
+@Subcomponent
+public interface IdleViewComponent {
+ /** Simple factory for {@link Factory}. */
+ @Subcomponent.Factory
+ interface Factory {
+ IdleViewComponent build(@BindsInstance IdleHostView idleHostView);
+ }
+
+ /** Builds a {@link IdleHostViewController}. */
+ IdleHostViewController getIdleHostViewController();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 62b92cb..0b8c635 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -18,14 +18,32 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionOldType;
+import static android.view.WindowManager.TransitionType;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Service;
+import android.app.WindowConfiguration;
import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -42,8 +60,13 @@
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
@@ -51,8 +74,11 @@
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.systemui.SystemUIApplication;
+import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
+import java.util.ArrayList;
+
import javax.inject.Inject;
public class KeyguardService extends Service {
@@ -79,40 +105,196 @@
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
public static boolean sEnableRemoteKeyguardGoingAwayAnimation =
- !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 1;
+ sEnableRemoteKeyguardAnimation >= 1;
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
public static boolean sEnableRemoteKeyguardOccludeAnimation =
- !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 2;
+ sEnableRemoteKeyguardAnimation >= 2;
private final KeyguardViewMediator mKeyguardViewMediator;
private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
+ private static int newModeToLegacyMode(int newMode) {
+ switch (newMode) {
+ case WindowManager.TRANSIT_OPEN:
+ case WindowManager.TRANSIT_TO_FRONT:
+ return MODE_OPENING;
+ case WindowManager.TRANSIT_CLOSE:
+ case WindowManager.TRANSIT_TO_BACK:
+ return MODE_CLOSING;
+ default:
+ return 2; // MODE_CHANGING
+ }
+ }
+
+ private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers) {
+ final ArrayList<RemoteAnimationTarget> out = new ArrayList<>();
+ for (int i = 0; i < info.getChanges().size(); i++) {
+ boolean changeIsWallpaper =
+ (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
+ if (wallpapers != changeIsWallpaper) continue;
+
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ final int taskId = taskInfo != null ? change.getTaskInfo().taskId : -1;
+ boolean isNotInRecents;
+ WindowConfiguration windowConfiguration = null;
+ if (taskInfo != null) {
+ if (taskInfo.getConfiguration() != null) {
+ windowConfiguration =
+ change.getTaskInfo().getConfiguration().windowConfiguration;
+ }
+ isNotInRecents = !change.getTaskInfo().isRunning;
+ } else {
+ isNotInRecents = true;
+ }
+ Rect localBounds = new Rect(change.getEndAbsBounds());
+ localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
+
+ out.add(new RemoteAnimationTarget(
+ taskId,
+ newModeToLegacyMode(change.getMode()),
+ change.getLeash(),
+ (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0
+ || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0,
+ null /* clipRect */,
+ new Rect(0, 0, 0, 0) /* contentInsets */,
+ info.getChanges().size() - i,
+ new Point(), localBounds, new Rect(change.getEndAbsBounds()),
+ windowConfiguration, isNotInRecents, null /* startLeash */,
+ change.getStartAbsBounds(), taskInfo, false /* allowEnterPip */));
+ }
+ return out.toArray(new RemoteAnimationTarget[out.size()]);
+ }
+
+ private static @TransitionOldType int getTransitionOldType(@TransitionType int type,
+ RemoteAnimationTarget[] apps) {
+ if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
+ return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+ : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+ } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE;
+ } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
+ return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+ } else {
+ Slog.d(TAG, "Unexpected transit type: " + type);
+ return TRANSIT_OLD_NONE;
+ }
+ }
+
+ private static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
+ return new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
+ final RemoteAnimationTarget[] apps = wrap(info, false /* wallpapers */);
+ final RemoteAnimationTarget[] wallpapers = wrap(info, true /* wallpapers */);
+ final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
+
+ // TODO: Remove this, and update alpha value in the IAnimationRunner.
+ for (TransitionInfo.Change change : info.getChanges()) {
+ t.setAlpha(change.getLeash(), 1.0f);
+ }
+ t.apply();
+ runner.onAnimationStart(getTransitionOldType(info.getType(), apps),
+ apps, wallpapers, nonApps,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+ finishCallback.onTransitionFinished(null /* wct */, null /* t */);
+ }
+ }
+ );
+ }
+
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+
+ }
+ };
+ }
+
@Inject
public KeyguardService(KeyguardViewMediator keyguardViewMediator,
- KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher) {
+ KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
+ ShellTransitions shellTransitions) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
- RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- if (sEnableRemoteKeyguardGoingAwayAnimation) {
- final RemoteAnimationAdapter exitAnimationAdapter =
- new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, exitAnimationAdapter);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- exitAnimationAdapter);
+ if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (sEnableRemoteKeyguardGoingAwayAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
+ TransitionFilter f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_GOING_AWAY};
+ shellTransitions.registerRemote(f, wrap(mExitAnimationRunner));
+ }
+ if (sEnableRemoteKeyguardOccludeAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
+ // Register for occluding
+ TransitionFilter f = new TransitionFilter();
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+ f.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ // First require at-least one app showing that occludes.
+ f.mRequirements[0].mMustBeIndependent = false;
+ f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ // Then require that we aren't closing any occludes (because this would mean a
+ // regular task->task or activity->activity animation not involving keyguard).
+ f.mRequirements[1].mNot = true;
+ f.mRequirements[1].mMustBeIndependent = false;
+ f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ shellTransitions.registerRemote(f, mOccludeAnimation);
+
+ // Now register for un-occlude.
+ f = new TransitionFilter();
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+ f.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ // First require at-least one app going-away (doesn't need occlude flag
+ // as that is implicit by it having been visible and we don't want to exclude
+ // cases where we are un-occluding because the app removed its showWhenLocked
+ // capability at runtime).
+ f.mRequirements[1].mMustBeIndependent = false;
+ f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ f.mRequirements[1].mMustBeTask = true;
+ // Then require that we aren't opening any occludes (otherwise we'd remain
+ // occluded).
+ f.mRequirements[0].mNot = true;
+ f.mRequirements[0].mMustBeIndependent = false;
+ f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ shellTransitions.registerRemote(f, mUnoccludeAnimation);
+ }
+ } else {
+ RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ if (sEnableRemoteKeyguardGoingAwayAnimation) {
+ final RemoteAnimationAdapter exitAnimationAdapter =
+ new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
+ exitAnimationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ exitAnimationAdapter);
+ }
+ if (sEnableRemoteKeyguardOccludeAnimation) {
+ final RemoteAnimationAdapter occludeAnimationAdapter =
+ new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
+ occludeAnimationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE,
+ occludeAnimationAdapter);
+ }
+ ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
+ DEFAULT_DISPLAY, definition);
}
- if (sEnableRemoteKeyguardOccludeAnimation) {
- final RemoteAnimationAdapter occludeAnimationAdapter =
- new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE, occludeAnimationAdapter);
- definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, occludeAnimationAdapter);
- }
- ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
- DEFAULT_DISPLAY, definition);
}
@Override
@@ -145,10 +327,10 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) {
- Trace.beginSection("KeyguardService.mBinder#startKeyguardExitAnimation");
+ Trace.beginSection("mExitAnimationRunner.onAnimationStart#startKeyguardExitAnimation");
checkPermission();
mKeyguardViewMediator.startKeyguardExitAnimation(transit, apps, wallpapers,
- null /* nonApps */, finishedCallback);
+ nonApps, finishedCallback);
Trace.endSection();
}
@@ -166,14 +348,14 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) {
+ Slog.d(TAG, "mOccludeAnimationRunner.onAnimationStart: transit=" + transit);
try {
if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
mBinder.setOccluded(true /* isOccluded */, true /* animate */);
} else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) {
mBinder.setOccluded(false /* isOccluded */, true /* animate */);
}
- // TODO(bc-unlock): Implement occlude/unocclude animation applied on apps,
- // wallpapers and nonApps.
+ // TODO(bc-unlock): Implement (un)occlude animation.
finishedCallback.onAnimationFinished();
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException");
@@ -185,6 +367,40 @@
}
};
+ final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ t.apply();
+ mBinder.setOccluded(true /* isOccluded */, true /* animate */);
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ }
+
+ @Override
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+ }
+ };
+
+ final IRemoteTransition mUnoccludeAnimation = new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ t.apply();
+ mBinder.setOccluded(false /* isOccluded */, true /* animate */);
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ }
+
+ @Override
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+ }
+ };
+
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 941f2c6..e51b602 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -31,7 +31,7 @@
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
@@ -222,6 +222,11 @@
keyguardViewController.hide(startTime, 350)
surfaceBehindEntryAnimator.start()
}
+
+ // Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
+ // Check it here in case there is no more change to the dismiss amount after the last change
+ // that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached()
+ finishKeyguardExitRemoteAnimationIfReachThreshold()
}
fun notifyCancelKeyguardExitAnimation() {
@@ -353,16 +358,6 @@
}
val dismissAmount = keyguardStateController.dismissAmount
-
- // Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
- // crossed the threshold to finish the dismissal.
- val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
- (keyguardStateController.isDismissingFromSwipe &&
- // Don't hide if we're flinging during a swipe, since we need to finish
- // animating it out. This will be called again after the fling ends.
- !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
- dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
-
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
// We passed the threshold, and we're not yet showing the surface behind the
@@ -375,9 +370,35 @@
// out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
- } else if (keyguardViewMediator.get()
- .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
- reachedHideKeyguardThreshold) {
+ } else {
+ finishKeyguardExitRemoteAnimationIfReachThreshold()
+ }
+ }
+
+ /**
+ * Hides the keyguard if we're fully dismissed, or if we're swiping to dismiss and have crossed
+ * the threshold to finish the dismissal.
+ */
+ private fun finishKeyguardExitRemoteAnimationIfReachThreshold() {
+ // no-op if keyguard is not showing or animation is not enabled.
+ if (!KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation ||
+ !keyguardViewController.isShowing) {
+ return
+ }
+
+ // no-op if animation is not requested yet.
+ if (!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
+ !keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
+ return
+ }
+
+ val dismissAmount = keyguardStateController.dismissAmount
+ if (dismissAmount >= 1f ||
+ (keyguardStateController.isDismissingFromSwipe &&
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) {
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c7c2590..b9834d4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -399,6 +399,12 @@
private boolean mPendingLock;
/**
+ * When starting to go away, flag a need to show the PIN lock so the keyguard can be brought
+ * back.
+ */
+ private boolean mPendingPinLock = false;
+
+ /**
* Whether a power button gesture (such as double tap for camera) has been detected. This is
* delivered directly from {@link KeyguardService}, immediately upon the gesture being detected.
* This is used in {@link #onStartedWakingUp} to decide whether to execute the pending lock, or
@@ -472,6 +478,19 @@
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ synchronized (KeyguardViewMediator.this) {
+ if (!showing && mPendingPinLock) {
+ Log.i(TAG, "PIN lock requested, starting keyguard");
+
+ // Bring the keyguard back in order to show the PIN lock
+ mPendingPinLock = false;
+ doKeyguardLocked(null);
+ }
+ }
+ }
+
+ @Override
public void onUserSwitching(int userId) {
if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
// Note that the mLockPatternUtils user has already been updated from setCurrentUser.
@@ -591,6 +610,7 @@
+ "showing; need to show keyguard so user can enter sim pin");
doKeyguardLocked(null);
} else {
+ mPendingPinLock = true;
resetStateLocked();
}
}
@@ -739,6 +759,9 @@
@Override
public void onBouncerVisiblityChanged(boolean shown) {
synchronized (KeyguardViewMediator.this) {
+ if (shown) {
+ mPendingPinLock = false;
+ }
adjustStatusBarLocked(shown, false);
}
}
@@ -2369,7 +2392,7 @@
final boolean wasShowing = mShowing;
onKeyguardExitFinished();
- if (mKeyguardStateController.isDismissingFromSwipe() || !wasShowing) {
+ if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) {
mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation();
}
@@ -2783,7 +2806,7 @@
}
}
- private void setShowingLocked(boolean showing) {
+ void setShowingLocked(boolean showing) {
setShowingLocked(showing, false /* forceCallbacks */);
}
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..4a67e94 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;
@@ -92,8 +94,8 @@
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -290,7 +292,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mNotificationRemoteInputManager.getController().isRemoteInputActive();
+ return !mNotificationRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -589,12 +591,13 @@
mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
return barView;
}
public void destroyView() {
+ setAutoHideController(/* autoHideController */ null);
mCommandQueue.removeCallback(this);
mContext.getSystemService(WindowManager.class).removeViewImmediate(
mNavigationBarView.getRootView());
@@ -917,6 +920,11 @@
@Override
public void onRotationProposal(final int rotation, boolean isValid) {
+ // The CommandQueue callbacks are added when the view is created to ensure we track other
+ // states, but until the view is attached (at the next traversal), the view's display is
+ // not valid. Just ignore the rotation in this case.
+ if (!mNavigationBarView.isAttachedToWindow()) return;
+
final int winRotation = mNavigationBarView.getDisplay().getRotation();
final boolean rotateSuggestionsDisabled = RotationButtonController
.hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -964,7 +972,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
if (displayId != mDisplayId) {
return;
}
@@ -1379,11 +1387,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);
}
}
@@ -1462,7 +1490,7 @@
}
/** Sets {@link AutoHideController} to the navigation bar. */
- public void setAutoHideController(AutoHideController autoHideController) {
+ private void setAutoHideController(AutoHideController autoHideController) {
mAutoHideController = autoHideController;
if (mAutoHideController != null) {
mAutoHideController.setNavigationBar(mAutoHideUiElement);
@@ -1511,7 +1539,7 @@
}
}
updateScreenPinningGestures();
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 458c50d..543004e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -402,7 +402,6 @@
void removeNavigationBar(int displayId) {
NavigationBar navBar = mNavigationBars.get(displayId);
if (navBar != null) {
- navBar.setAutoHideController(/* autoHideController */ null);
navBar.destroyView();
mNavigationBars.remove(displayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 808b7e2..2d36de3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -98,6 +98,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
public class NavigationBarView extends FrameLayout implements
@@ -354,6 +355,7 @@
mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class)
.create(mContext);
mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates);
+ Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@Override
@@ -376,7 +378,7 @@
public boolean isSamplingEnabled() {
return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode);
}
- });
+ }, backgroundExecutor);
mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 1d44146..fe24ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -26,7 +26,7 @@
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.model.SysUiState;
@@ -109,7 +109,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
- InsetsState requestedState, String packageName) {
+ InsetsVisibilities requestedVisibilities, String packageName) {
mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 7fdb79e..ea04cef 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.VibratorHelper;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPlugin {
@@ -349,6 +350,7 @@
.getDimension(R.dimen.navigation_edge_action_drag_threshold);
setVisibility(GONE);
+ Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@@ -366,7 +368,7 @@
public boolean isSamplingEnabled() {
return isPrimaryDisplay;
}
- });
+ }, backgroundExecutor);
mRegionSamplingHelper.setWindowVisible(true);
mShowProtection = !isPrimaryDisplay;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
index 560d89a..c9a9399 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
@@ -30,6 +30,7 @@
import com.android.systemui.R;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
/**
* A helper class to sample regions on the screen and inspect its luminosity.
@@ -52,6 +53,7 @@
*/
private final Rect mRegisteredSamplingBounds = new Rect();
private final SamplingCallback mCallback;
+ private final Executor mBackgroundExecutor;
private boolean mSamplingEnabled = false;
private boolean mSamplingListenerRegistered = false;
@@ -82,7 +84,9 @@
}
};
- public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback) {
+ public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
+ Executor backgroundExecutor) {
+ mBackgroundExecutor = backgroundExecutor;
mSamplingListener = new CompositionSamplingListener(
sampledView.getContext().getMainExecutor()) {
@Override
@@ -183,10 +187,13 @@
// We only want to reregister if something actually changed
unregisterSamplingListener();
mSamplingListenerRegistered = true;
- CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
- stopLayerControl, mSamplingRequestBounds);
+ SurfaceControl registeredStopLayer = stopLayerControl;
+ mBackgroundExecutor.execute(() -> {
+ CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+ registeredStopLayer, mSamplingRequestBounds);
+ });
mRegisteredSamplingBounds.set(mSamplingRequestBounds);
- mRegisteredStopLayer = stopLayerControl;
+ mRegisteredStopLayer = registeredStopLayer;
}
mFirstSamplingAfterStart = false;
} else {
@@ -199,7 +206,9 @@
mSamplingListenerRegistered = false;
mRegisteredStopLayer = null;
mRegisteredSamplingBounds.setEmpty();
- CompositionSamplingListener.unregister(mSamplingListener);
+ mBackgroundExecutor.execute(() -> {
+ CompositionSamplingListener.unregister(mSamplingListener);
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a318073..4fcd46c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -423,6 +423,9 @@
if (mQsPanelController.shouldUseHorizontalLayout()
&& mQsPanelController.mMediaHost.hostView != null) {
builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
+ } else {
+ // In portrait, media view should always be visible
+ mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
}
mAllPagesDelayedAnimator = builder.build();
mAllViews.add(mSecurityFooter.getView());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index adcaf5d..a128694 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -29,13 +29,17 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.qs.customize.QSCustomizer;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Wrapper view with background which contains {@link QSPanel} and {@link QuickStatusBarHeader}
*/
-public class QSContainerImpl extends FrameLayout {
+public class QSContainerImpl extends FrameLayout implements Dumpable {
private final Point mSizePoint = new Point();
private int mFancyClippingTop;
@@ -302,4 +306,11 @@
mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
invalidate();
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(getClass().getSimpleName() + " updateClippingPath: top("
+ + mFancyClippingTop + ") bottom(" + mFancyClippingBottom + ") mClippingEnabled("
+ + mClippingEnabled + ")");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 2d7bfcd..f754494 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -37,8 +37,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
@@ -46,9 +48,9 @@
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.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.InjectionInflationController;
@@ -70,6 +72,7 @@
private final Rect mQsBounds = new Rect();
private final StatusBarStateController mStatusBarStateController;
private final FalsingManager mFalsingManager;
+ private final KeyguardBypassController mBypassController;
private boolean mQsExpanded;
private boolean mHeaderAnimating;
private boolean mStackScrollerOverscrolling;
@@ -113,7 +116,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.
@@ -131,14 +133,17 @@
*/
private boolean mAnimateNextQsUpdate;
+ private DumpManager mDumpManager;
+
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
InjectionInflationController injectionInflater, QSTileHost qsTileHost,
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
- QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags,
- FalsingManager falsingManager) {
+ KeyguardBypassController keyguardBypassController,
+ QSFragmentComponent.Factory qsComponentFactory,
+ FalsingManager falsingManager, DumpManager dumpManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
mCommandQueue = commandQueue;
@@ -148,9 +153,10 @@
mQsComponentFactory = qsComponentFactory;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
- mFeatureFlags = featureFlags;
mFalsingManager = falsingManager;
+ mBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mDumpManager = dumpManager;
}
@Override
@@ -196,6 +202,7 @@
mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
+ mDumpManager.registerDumpable(mContainer.getClass().getName(), mContainer);
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
mQSAnimator = qsFragmentComponent.getQSAnimator();
@@ -247,6 +254,7 @@
mQSCustomizerController.setQs(null);
mQsDetailDisplayer.setQsPanelController(null);
mScrollListener = null;
+ mDumpManager.unregisterDumpable(mContainer.getClass().getName());
}
@Override
@@ -377,7 +385,7 @@
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
mQsDragHandler.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
- && Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources())
+ && Utils.shouldUseSplitNotificationShade(getResources())
? View.VISIBLE
: View.GONE);
}
@@ -388,16 +396,8 @@
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
}
- @Override
- public void setPulseExpanding(boolean pulseExpanding) {
- if (pulseExpanding != mPulseExpanding) {
- mPulseExpanding = pulseExpanding;
- updateShowCollapsedOnKeyguard();
- }
- }
-
private void updateShowCollapsedOnKeyguard() {
- boolean showCollapsed = mPulseExpanding || mTransitioningToFullShade;
+ boolean showCollapsed = mBypassController.getBypassEnabled() || mTransitioningToFullShade;
if (showCollapsed != mShowCollapsedOnKeyguard) {
mShowCollapsedOnKeyguard = showCollapsed;
updateQsState();
@@ -727,5 +727,6 @@
public void onStateChanged(int newState) {
mState = newState;
setKeyguardShowing(newState == StatusBarState.KEYGUARD);
+ updateShowCollapsedOnKeyguard();
}
}
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/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 756ad99..240cf93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -39,6 +39,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -51,7 +52,6 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
-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;
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..8cb9d46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -32,9 +32,11 @@
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;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
@@ -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,16 @@
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;
+
+ private boolean mHasCenterCutout;
+ private boolean mConfigShowBatteryEstimate;
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 +155,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 +168,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);
@@ -200,6 +211,14 @@
mPrivacyContainer.setLayoutParams(lp);
}
+ private void updateBatteryMode() {
+ if (mConfigShowBatteryEstimate && !mHasCenterCutout) {
+ mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+ } else {
+ mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ON);
+ }
+ }
+
void updateResources() {
Resources resources = mContext.getResources();
// status bar is already displayed out of QS in split shade
@@ -208,6 +227,8 @@
mStatusIconsView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
mDatePrivacyView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
+ mConfigShowBatteryEstimate = resources.getBoolean(R.bool.config_showBatteryEstimateQSBH);
+
mRoundedCornerPadding = resources.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
@@ -248,6 +269,7 @@
.getDimensionPixelSize(R.dimen.qqs_layout_margin_top);
mHeaderQsPanel.setLayoutParams(qqsLP);
+ updateBatteryMode();
updateHeadersPadding();
updateAnimators();
}
@@ -274,13 +296,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 +306,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();
@@ -405,14 +414,14 @@
mClockIconsSeparatorLayoutParams.width = 0;
setSeparatorVisibility(false);
mShowClockIconsSeparator = false;
- mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+ mHasCenterCutout = false;
} else {
datePrivacySeparatorLayoutParams.width = topCutout.width();
mDatePrivacySeparator.setVisibility(View.VISIBLE);
mClockIconsSeparatorLayoutParams.width = topCutout.width();
mShowClockIconsSeparator = true;
setSeparatorVisibility(mKeyguardExpansionFraction == 0f);
- mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ON);
+ mHasCenterCutout = true;
}
}
mDatePrivacySeparator.setLayoutParams(datePrivacySeparatorLayoutParams);
@@ -420,6 +429,8 @@
mCutOutPaddingLeft = padding.first;
mCutOutPaddingRight = padding.second;
mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
+
+ updateBatteryMode();
updateHeadersPadding();
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 396f334..6c57c77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -25,9 +25,11 @@
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.privacy.PrivacyChipEvent;
@@ -37,14 +39,12 @@
import com.android.systemui.privacy.logging.PrivacyLogger;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
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;
@@ -72,6 +72,7 @@
private final PrivacyDialogController mPrivacyDialogController;
private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
private final FeatureFlags mFeatureFlags;
+ private final BatteryMeterViewController mBatteryMeterViewController;
private final VariableDateViewController mVariableDateViewControllerDateView;
private final VariableDateViewController mVariableDateViewControllerClockDateView;
@@ -80,6 +81,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 +112,7 @@
}
private void update() {
- StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ updatePrivacyIconSlots();
setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
}
};
@@ -138,7 +141,8 @@
PrivacyDialogController privacyDialogController,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
FeatureFlags featureFlags,
- VariableDateViewController.Factory variableDateViewControllerFactory) {
+ VariableDateViewController.Factory variableDateViewControllerFactory,
+ BatteryMeterViewController batteryMeterViewController) {
super(view);
mPrivacyItemController = privacyItemController;
mActivityStarter = activityStarter;
@@ -150,6 +154,7 @@
mPrivacyDialogController = privacyDialogController;
mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
mFeatureFlags = featureFlags;
+ mBatteryMeterViewController = batteryMeterViewController;
mQSCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
@@ -165,7 +170,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 +178,15 @@
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
+ protected void onInit() {
+ mBatteryMeterViewController.init();
}
@Override
@@ -183,14 +197,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 +233,7 @@
mColorExtractor.removeOnColorsChangedListener(mOnColorsChangedListener);
mPrivacyChip.setOnClickListener(null);
mStatusBarIconController.removeIconGroup(mIconManager);
+ mQSCarrierGroupController.setOnSingleCarrierChangedListener(null);
mDemoModeController.removeCallback(mDemoModeReceiver);
setListening(false);
}
@@ -250,21 +281,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..953f9fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -37,10 +37,11 @@
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.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.util.CarrierConfigTracker;
@@ -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/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3cb715c..1770807 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -34,6 +34,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
@@ -41,7 +42,6 @@
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 6fa44eb..103ac65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -20,7 +20,7 @@
import android.hardware.display.ColorDisplayManager;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.util.settings.GlobalSettings;
import javax.inject.Named;
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..2046550 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -23,6 +23,7 @@
import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSContainerImpl;
@@ -109,6 +110,12 @@
/** */
@Provides
+ static BatteryMeterView providesBatteryMeterView(QuickStatusBarHeader quickStatusBarHeader) {
+ return quickStatusBarHeader.findViewById(R.id.batteryRemainingIcon);
+ }
+
+ /** */
+ @Provides
static QSFooterView providesQSFooterView(@RootView View view) {
return view.findViewById(R.id.qs_footer);
}
@@ -145,5 +152,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/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index f66b722..bc21b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -69,7 +69,7 @@
private var hasControlsApps = AtomicBoolean(false)
- private val icon = ResourceIcon.get(R.drawable.ic_device_light)
+ private val icon = ResourceIcon.get(R.drawable.controls_icon)
private val listingCallback = object : ControlsListingController.ControlsListingCallback {
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
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 ce1c2fd..f303aa9 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
@@ -79,11 +79,11 @@
InternetDialogController.InternetDialogCallback, Window.Callback {
private static final String TAG = "InternetDialog";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ static final long PROGRESS_DELAY_MS = 2000L;
+
private final Handler mHandler;
private final LinearLayoutManager mLayoutManager;
- private final Runnable mHideProgressBarRunnable = () -> {
- setProgressBarVisible(false);
- };
@VisibleForTesting
protected InternetAdapter mAdapter;
@@ -101,6 +101,7 @@
private InternetDialogController mInternetDialogController;
private TextView mInternetDialogTitle;
private TextView mInternetDialogSubTitle;
+ private View mDivider;
private ProgressBar mProgressBar;
private LinearLayout mInternetListLayout;
private LinearLayout mConnectedWifListLayout;
@@ -125,9 +126,19 @@
private WifiEntry mConnectedWifiEntry;
private int mListMaxHeight;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private boolean mIsProgressBarVisible;
private boolean mCanConfigMobileData;
+ // Wi-Fi scanning progress bar
+ protected boolean mIsProgressBarVisible;
+ protected boolean mIsSearchingHidden;
+ protected final Runnable mHideProgressBarRunnable = () -> {
+ setProgressBarVisible(false);
+ };
+ protected Runnable mHideSearchingRunnable = () -> {
+ mIsSearchingHidden = true;
+ mInternetDialogSubTitle.setText(getSubtitleText());
+ };
+
private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
// Set max height for list
if (mInternetListLayout.getHeight() > mListMaxHeight) {
@@ -195,6 +206,7 @@
mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+ mDivider = mDialogView.requireViewById(R.id.divider);
mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
mInternetListLayout = mDialogView.requireViewById(R.id.internet_list);
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
@@ -243,6 +255,7 @@
Log.d(TAG, "onStop");
}
mHandler.removeCallbacks(mHideProgressBarRunnable);
+ mHandler.removeCallbacks(mHideSearchingRunnable);
mMobileNetworkLayout.setOnClickListener(null);
mMobileDataToggle.setOnCheckedChangeListener(null);
mConnectedWifListLayout.setOnClickListener(null);
@@ -374,7 +387,8 @@
}
CharSequence getSubtitleText() {
- return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
+ return mInternetDialogController.getSubtitleText(
+ mIsProgressBarVisible && !mIsSearchingHidden);
}
private Drawable getConnectedWifiDrawable() {
@@ -406,7 +420,7 @@
return mInternetDialogController.getConnectedWifiSummary();
}
- private void showProgressBar() {
+ protected void showProgressBar() {
if (mWifiManager == null || !mWifiManager.isWifiEnabled()) {
setProgressBarVisible(false);
return;
@@ -414,8 +428,9 @@
setProgressBarVisible(true);
List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
if (wifiScanResults != null && wifiScanResults.size() > 0) {
- mContext.getMainThreadHandler().postDelayed(mHideProgressBarRunnable,
- 2000 /* delay millis */);
+ mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
+ } else if (!mIsSearchingHidden) {
+ mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
}
}
@@ -425,7 +440,8 @@
mIsProgressBarVisible = true;
}
mIsProgressBarVisible = visible;
- mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.INVISIBLE);
+ mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.GONE);
+ mDivider.setVisibility(mIsProgressBarVisible ? View.GONE : View.VISIBLE);
mInternetDialogSubTitle.setText(getSubtitleText());
}
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 edab33a..8123fc8 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
@@ -269,17 +269,17 @@
return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF);
}
+ final List<ScanResult> wifiList = mWifiManager.getScanResults();
+ if (wifiList != null && wifiList.size() != 0) {
+ return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
+ }
+
if (isProgressBarVisible) {
// When the Wi-Fi scan result callback is received
// Sub-Title: Searching for networks...
return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS);
}
- final List<ScanResult> wifiList = mWifiManager.getScanResults();
- if (wifiList != null && wifiList.size() != 0) {
- return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
- }
-
// Sub-Title:
// show non_carrier_network_unavailable
// - while Wi-Fi on + no Wi-Fi item
@@ -318,7 +318,7 @@
Drawable getWifiConnectedDrawable(WifiEntry wifiEntry) throws Throwable {
final @ColorInt int tint;
tint = Utils.getColorAttrDefaultColor(mContext,
- com.android.internal.R.attr.colorAccentPrimaryVariant);
+ com.android.internal.R.attr.colorControlNormal);
final Drawable drawable = mContext.getDrawable(
com.android.settingslib.Utils.getWifiIconResource(wifiEntry.getLevel()));
drawable.setTint(tint);
@@ -345,11 +345,6 @@
drawable.setTint(
Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal));
- if (activeNetworkIsCellular()) {
- drawable.setTint(Utils.getColorAttrDefaultColor(mContext,
- com.android.internal.R.attr.colorAccentPrimaryVariant));
- }
-
} catch (Throwable e) {
e.printStackTrace();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index ce6e469..93e5021 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -45,9 +45,12 @@
import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Background;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.Executor;
+
import javax.inject.Inject;
/**
@@ -63,6 +66,8 @@
private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
+ private final Executor mBgExecutor;
+
/**
* Represents the connection to a target window and provides a mechanism for requesting tiles.
*/
@@ -155,8 +160,10 @@
private IBinder mHostWindowToken;
@Inject
- public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) {
+ public ScrollCaptureClient(IWindowManager windowManagerService,
+ @Background Executor bgExecutor, @UiContext Context context) {
requireNonNull(context.getDisplay(), "context must be associated with a Display!");
+ mBgExecutor = bgExecutor;
mWindowManagerService = windowManagerService;
}
@@ -220,21 +227,25 @@
return "";
}
SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(),
- response.getBoundsInWindow(), maxPages);
+ response.getBoundsInWindow(), maxPages, mBgExecutor);
session.start(completer);
return "IScrollCaptureCallbacks#onCaptureStarted";
});
}
private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session,
- IBinder.DeathRecipient {
+ IBinder.DeathRecipient, ImageReader.OnImageAvailableListener {
private IScrollCaptureConnection mConnection;
+ private final Executor mBgExecutor;
+ private final Object mLock = new Object();
private ImageReader mReader;
private final int mTileHeight;
private final int mTileWidth;
private Rect mRequestRect;
+ private Rect mCapturedArea;
+ private Image mCapturedImage;
private boolean mStarted;
private final int mTargetHeight;
@@ -247,7 +258,8 @@
private Completer<Void> mEndCompleter;
private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds,
- Rect boundsInWindow, float maxPages) throws RemoteException {
+ Rect boundsInWindow, float maxPages, Executor bgExecutor)
+ throws RemoteException {
mConnection = requireNonNull(connection);
mConnection.asBinder().linkToDeath(SessionWrapper.this, 0);
mWindowBounds = requireNonNull(windowBounds);
@@ -259,7 +271,7 @@
mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width();
mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
-
+ mBgExecutor = bgExecutor;
if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
@@ -289,6 +301,7 @@
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer;
+ mReader.setOnImageAvailableListenerWithExecutor(this, mBgExecutor);
try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
completer.addCancellationListener(() -> {
@@ -339,9 +352,34 @@
@BinderThread
@Override
- public void onImageRequestCompleted(int flags, Rect contentArea) {
- Image image = mReader.acquireLatestImage();
- mTileRequestCompleter.set(new CaptureResult(image, mRequestRect, contentArea));
+ public void onImageRequestCompleted(int flagsUnused, Rect contentArea) {
+ synchronized (mLock) {
+ mCapturedArea = contentArea;
+ if (mCapturedImage != null || (mCapturedArea == null || mCapturedArea.isEmpty())) {
+ completeCaptureRequest();
+ }
+ }
+ }
+
+ /** @see ImageReader.OnImageAvailableListener */
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ synchronized (mLock) {
+ mCapturedImage = mReader.acquireLatestImage();
+ if (mCapturedArea != null) {
+ completeCaptureRequest();
+ }
+ }
+ }
+
+ /** Produces a result for the caller as soon as both asynchronous results are received. */
+ private void completeCaptureRequest() {
+ CaptureResult result =
+ new CaptureResult(mCapturedImage, mRequestRect, mCapturedArea);
+ mCapturedImage = null;
+ mRequestRect = null;
+ mCapturedArea = null;
+ mTileRequestCompleter.set(result);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c7f8dcf..90158c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -50,8 +50,8 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -338,7 +338,8 @@
*/
default void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) { }
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) { }
/**
* @see IStatusBar#showTransient(int, int[]).
@@ -997,7 +998,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = displayId;
@@ -1005,7 +1006,7 @@
args.argi3 = navbarColorManagedByIme ? 1 : 0;
args.arg1 = appearanceRegions;
args.argi4 = behavior;
- args.arg2 = requestedState;
+ args.arg2 = requestedVisibilities;
args.arg3 = packageName;
mHandler.obtainMessage(MSG_SYSTEM_BAR_CHANGED, args).sendToTarget();
}
@@ -1389,7 +1390,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onSystemBarAttributesChanged(args.argi1, args.argi2,
(AppearanceRegion[]) args.arg1, args.argi3 == 1, args.argi4,
- (InsetsState) args.arg2, (String) args.arg3);
+ (InsetsVisibilities) args.arg2, (String) args.arg3);
}
args.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 44399a1..3890c1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -77,6 +77,7 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -94,13 +95,13 @@
* 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;
private static final int MSG_HIDE_TRANSIENT = 1;
- private static final int MSG_SWIPE_UP_TO_UNLOCK = 2;
+ private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
@@ -121,6 +122,7 @@
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
private final FalsingManager mFalsingManager;
+ private final KeyguardBypassController mKeyguardBypassController;
protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
@@ -175,7 +177,8 @@
@Main DelayableExecutor executor,
FalsingManager falsingManager,
LockPatternUtils lockPatternUtils,
- IActivityManager iActivityManager) {
+ IActivityManager iActivityManager,
+ KeyguardBypassController keyguardBypassController) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -191,6 +194,7 @@
mLockPatternUtils = lockPatternUtils;
mIActivityManager = iActivityManager;
mFalsingManager = falsingManager;
+ mKeyguardBypassController = keyguardBypassController;
}
@@ -206,7 +210,7 @@
mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
mStatusBarStateController.addCallback(mStatusBarStateListener);
- mKeyguardStateController.addCallback(this);
+ mKeyguardStateController.addCallback(mKeyguardStateCallback);
mStatusBarStateListener.onDozingChanged(mStatusBarStateController.isDozing());
}
@@ -593,7 +597,7 @@
mTransientIndication = transientIndication;
mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
- mHandler.removeMessages(MSG_SWIPE_UP_TO_UNLOCK);
+ mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
// Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
mWakeLock.setAcquired(true);
@@ -785,27 +789,45 @@
public void handleMessage(Message msg) {
if (msg.what == MSG_HIDE_TRANSIENT) {
hideTransientIndication();
- } else if (msg.what == MSG_SWIPE_UP_TO_UNLOCK) {
- showSwipeUpToUnlock();
+ } else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
+ showActionToUnlock();
}
}
};
- private void showSwipeUpToUnlock() {
+ /**
+ * Show message on the keyguard for how the user can unlock/enter their device.
+ */
+ public void showActionToUnlock() {
if (mDozing) {
return;
}
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
- return; // udfps affordance is highlighted, no need to surface face auth error
- } else {
+ return; // udfps affordance is highlighted, no need to show action to unlock
+ } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
String message = mContext.getString(R.string.keyguard_retry);
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
}
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock),
- false /* isError */, true /* hideOnScreenOff */);
+ if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock_press),
+ false /* isError */, true /* hideOnScreenOff */);
+ } else {
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock),
+ false /* isError */, true /* hideOnScreenOff */);
+ }
+ }
+ }
+
+ private void showTryFingerprintMsg() {
+ if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+ // if udfps available, there will always be a tappable affordance to unlock
+ // For example, the lock icon
+ showTransientIndication(R.string.keyguard_unlock_press);
+ } else {
+ showTransientIndication(R.string.keyguard_try_fingerprint);
}
}
@@ -827,11 +849,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;
@@ -884,7 +901,7 @@
return;
}
- boolean showSwipeToUnlock =
+ boolean showActionToUnlock =
msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
@@ -892,14 +909,12 @@
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
return;
}
- showTransientIndication(helpString, false /* isError */, showSwipeToUnlock);
- }
- if (showSwipeToUnlock) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWIPE_UP_TO_UNLOCK),
+ showTransientIndication(helpString, false /* isError */, showActionToUnlock);
+ } else if (showActionToUnlock) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
}
}
@@ -914,8 +929,7 @@
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()
&& !mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isScreenOn()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -924,16 +938,15 @@
if (!mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()
&& mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
} else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
mStatusBarKeyguardViewManager.showBouncerMessage(
- mContext.getResources().getString(R.string.keyguard_try_fingerprint),
+ mContext.getResources().getString(R.string.keyguard_unlock_press),
mInitialTextColorState
);
} else {
// suggest swiping up to unlock (try face auth again or swipe up to bouncer)
- showSwipeUpToUnlock();
+ showActionToUnlock();
}
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
@@ -967,10 +980,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 */);
}
@@ -1017,6 +1028,11 @@
boolean isStrongBiometric) {
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
+
+ if (biometricSourceType == BiometricSourceType.FACE
+ && !mKeyguardBypassController.canBypass()) {
+ mHandler.sendEmptyMessage(MSG_SHOW_ACTION_TO_UNLOCK);
+ }
}
@Override
@@ -1068,4 +1084,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..ca18b07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -60,11 +60,11 @@
private val mediaHierarchyManager: MediaHierarchyManager,
private val scrimController: ScrimController,
private val depthController: NotificationShadeDepthController,
- private val featureFlags: FeatureFlags,
private val context: Context,
configurationController: ConfigurationController,
falsingManager: FalsingManager
) {
+ private var pulseHeight: Float = 0f
private var useSplitShade: Boolean = false
private lateinit var nsslController: NotificationStackScrollLayoutController
lateinit var notificationPanelController: NotificationPanelViewController
@@ -88,6 +88,12 @@
internal var dragDownAnimator: ValueAnimator? = null
/**
+ * The current pulse height animator if any
+ */
+ @VisibleForTesting
+ internal var pulseHeightAnimator: ValueAnimator? = null
+
+ /**
* Distance that the full shade transition takes in order for scrim to fully transition to
* the shade (in alpha)
*/
@@ -110,6 +116,12 @@
private var nextHideKeyguardNeedsNoAnimation = false
/**
+ * The distance until we're showing the notifications when pulsing
+ */
+ val distanceUntilShowingPulsingNotifications
+ get() = scrimTransitionDistance
+
+ /**
* The udfpsKeyguardViewController if it exists.
*/
var udfpsKeyguardViewController: UdfpsKeyguardViewController? = null
@@ -134,7 +146,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) {
@@ -286,22 +298,26 @@
nsslController.setTransitionToFullShadeAmount(field)
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
- val scrimProgress = MathUtils.saturate(field / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
// TODO: appear qs also in split shade
val qsAmount = if (useSplitShade) 0f else field
qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */)
// TODO: appear media also in split shade
val mediaAmount = if (useSplitShade) 0f else field
mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount)
- // Fade out all content only visible on the lockscreen
- notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
- depthController.transitionToFullShadeProgress = scrimProgress
- udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
+ transitionToShadeAmountCommon(field)
}
}
}
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ // Fade out all content only visible on the lockscreen
+ notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
+ depthController.transitionToFullShadeProgress = scrimProgress
+ udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
+ }
+
private fun setDragDownAmountAnimated(
target: Float,
delay: Long = 0,
@@ -453,15 +469,19 @@
/**
* Notify this handler that the keyguard was just dismissed and that a animation to
* the full shade should happen.
+ *
+ * @param delay the delay to do the animation with
+ * @param previousState which state were we in when we hid the keyguard?
*/
- fun onHideKeyguard(delay: Long) {
+ fun onHideKeyguard(delay: Long, previousState: Int) {
if (animationHandlerOnKeyguardDismiss != null) {
animationHandlerOnKeyguardDismiss!!.invoke(delay)
animationHandlerOnKeyguardDismiss = null
} else {
if (nextHideKeyguardNeedsNoAnimation) {
nextHideKeyguardNeedsNoAnimation = false
- } else {
+ } else if (previousState != StatusBarState.SHADE_LOCKED) {
+ // No animation necessary if we already were in the shade locked!
performDefaultGoToFullShadeAnimation(delay)
}
}
@@ -479,6 +499,53 @@
notificationPanelController.animateToFullShade(delay)
animateAppear(delay)
}
+
+ //
+ // PULSE EXPANSION
+ //
+
+ /**
+ * Set the height how tall notifications are pulsing. This is only set whenever we are expanding
+ * from a pulse and determines how much the notifications are expanded.
+ */
+ fun setPulseHeight(height: Float, animate: Boolean = false) {
+ if (animate) {
+ val pulseHeightAnimator = ValueAnimator.ofFloat(pulseHeight, height)
+ pulseHeightAnimator.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ pulseHeightAnimator.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+ pulseHeightAnimator.addUpdateListener { animation: ValueAnimator ->
+ setPulseHeight(animation.animatedValue as Float)
+ }
+ pulseHeightAnimator.start()
+ this.pulseHeightAnimator = pulseHeightAnimator
+ } else {
+ pulseHeight = height
+ val overflow = nsslController.setPulseHeight(height)
+ notificationPanelController.setOverStrechAmount(overflow)
+ val transitionHeight = if (keyguardBypassController.bypassEnabled) height else 0.0f
+ transitionToShadeAmountCommon(transitionHeight)
+ }
+ }
+
+ /**
+ * Finish the pulse animation when the touch interaction finishes
+ * @param cancelled was the interaction cancelled and this is a reset?
+ */
+ fun finishPulseAnimation(cancelled: Boolean) {
+ if (cancelled) {
+ setPulseHeight(0f, animate = true)
+ } else {
+ notificationPanelController.onPulseExpansionFinished()
+ setPulseHeight(0f, animate = false)
+ }
+ }
+
+ /**
+ * Notify this class that a pulse expansion is starting
+ */
+ fun onPulseExpansionStarted() {
+ pulseHeightAnimator?.cancel()
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 8969b4d..36d2d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -52,6 +52,7 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.SmartspaceMediaData;
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/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index b34bfad..761a203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -19,8 +19,8 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Context
+import android.content.res.Configuration
import android.os.PowerManager
import android.os.PowerManager.WAKE_REASON_GESTURE
import android.os.SystemClock
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import kotlin.math.max
@@ -56,18 +57,17 @@
private val bypassController: KeyguardBypassController,
private val headsUpManager: HeadsUpManagerPhone,
private val roundnessManager: NotificationRoundnessManager,
+ private val configurationController: ConfigurationController,
private val statusBarStateController: StatusBarStateController,
private val falsingManager: FalsingManager,
private val lockscreenShadeTransitionController: LockscreenShadeTransitionController,
private val falsingCollector: FalsingCollector
) : Gefingerpoken {
companion object {
- private val RUBBERBAND_FACTOR_STATIC = 0.25f
private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
}
private val mPowerManager: PowerManager?
- private val mMinDragDistance: Int
private var mInitialTouchX: Float = 0.0f
private var mInitialTouchY: Float = 0.0f
var isExpanding: Boolean = false
@@ -81,6 +81,7 @@
topEntry?.let {
roundnessManager.setTrackingHeadsUp(it.row)
}
+ lockscreenShadeTransitionController.onPulseExpansionStarted()
} else {
roundnessManager.setTrackingHeadsUp(null)
if (!leavingLockscreen) {
@@ -93,8 +94,8 @@
}
var leavingLockscreen: Boolean = false
private set
- private val mTouchSlop: Float
- private lateinit var overStretchHandler: OverStretchHandler
+ private var touchSlop = 0f
+ private var minDragDistance = 0
private lateinit var stackScrollerController: NotificationStackScrollLayoutController
private val mTemp2 = IntArray(2)
private var mDraggedFarEnough: Boolean = false
@@ -102,9 +103,7 @@
private var mPulsing: Boolean = false
var isWakingToShadeLocked: Boolean = false
private set
- private var overStretchAmount: Float = 0.0f
- private var mWakeUpHeight: Float = 0.0f
- private var mReachedWakeUpHeight: Boolean = false
+
private var velocityTracker: VelocityTracker? = null
private val isFalseTouch: Boolean
@@ -114,12 +113,21 @@
var bouncerShowing: Boolean = false
init {
- mMinDragDistance = context.resources.getDimensionPixelSize(
- R.dimen.keyguard_drag_down_min_distance)
- mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
+ initResources(context)
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ initResources(context)
+ }
+ })
mPowerManager = context.getSystemService(PowerManager::class.java)
}
+ private fun initResources(context: Context) {
+ minDragDistance = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance)
+ touchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
+ }
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return canHandleMotionEvent() && startExpansion(event)
}
@@ -148,14 +156,12 @@
MotionEvent.ACTION_MOVE -> {
val h = y - mInitialTouchY
- if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
falsingCollector.onStartExpandingFromPulse()
isExpanding = true
captureStartingChild(mInitialTouchX, mInitialTouchY)
mInitialTouchY = y
mInitialTouchX = x
- mWakeUpHeight = wakeUpCoordinator.getWakeUpHeight()
- mReachedWakeUpHeight = false
return true
}
}
@@ -216,7 +222,6 @@
}
private fun finishExpansion() {
- resetClock()
val startingChild = mStartingChild
if (mStartingChild != null) {
setUserLocked(mStartingChild!!, false)
@@ -230,6 +235,7 @@
}
lockscreenShadeTransitionController.goToLockedShade(startingChild,
needsQSAnimation = false)
+ lockscreenShadeTransitionController.finishPulseAnimation(cancelled = false)
leavingLockscreen = true
isExpanding = false
if (mStartingChild is ExpandableNotificationRow) {
@@ -240,24 +246,19 @@
private fun updateExpansionHeight(height: Float) {
var expansionHeight = max(height, 0.0f)
- if (!mReachedWakeUpHeight && height > mWakeUpHeight) {
- mReachedWakeUpHeight = true
- }
if (mStartingChild != null) {
val child = mStartingChild!!
val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(),
child.maxContentHeight)
child.actualHeight = newHeight
- expansionHeight = max(newHeight.toFloat(), expansionHeight)
} else {
- val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f
- wakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
- true /* animate */,
- true /* increaseSpeed */)
- expansionHeight = max(mWakeUpHeight, expansionHeight)
+ wakeUpCoordinator.setNotificationsVisibleForExpansion(
+ height
+ > lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications,
+ true /* animate */,
+ true /* increaseSpeed */)
}
- val dragDownAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
- setOverStretchAmount(dragDownAmount)
+ lockscreenShadeTransitionController.setPulseHeight(expansionHeight, animate = false)
}
private fun captureStartingChild(x: Float, y: Float) {
@@ -269,11 +270,6 @@
}
}
- private fun setOverStretchAmount(amount: Float) {
- overStretchAmount = amount
- overStretchHandler.setOverStretchAmount(amount)
- }
-
private fun reset(child: ExpandableView) {
if (child.actualHeight == child.collapsedHeight) {
setUserLocked(child, false)
@@ -297,25 +293,14 @@
}
}
- private fun resetClock() {
- val anim = ValueAnimator.ofFloat(overStretchAmount, 0f)
- anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
- anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
- anim.addUpdateListener {
- animation -> setOverStretchAmount(animation.animatedValue as Float)
- }
- anim.start()
- }
-
private fun cancelExpansion() {
isExpanding = false
falsingCollector.onExpansionFromPulseStopped()
if (mStartingChild != null) {
reset(mStartingChild!!)
mStartingChild = null
- } else {
- resetClock()
}
+ lockscreenShadeTransitionController.finishPulseAnimation(cancelled = true)
wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
true /* animate */,
false /* increaseSpeed */)
@@ -333,11 +318,7 @@
} else null
}
- fun setUp(
- stackScrollerController: NotificationStackScrollLayoutController,
- overStrechHandler: OverStretchHandler
- ) {
- this.overStretchHandler = overStrechHandler
+ fun setUp(stackScrollerController: NotificationStackScrollLayoutController) {
this.stackScrollerController = stackScrollerController
}
@@ -348,12 +329,4 @@
fun onStartedWakingUp() {
isWakingToShadeLocked = false
}
-
- interface OverStretchHandler {
-
- /**
- * Set the overstretch amount in pixels This will be rubberbanded later
- */
- fun setOverStretchAmount(amount: Float)
- }
}
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/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index d4f5bd2..545dca8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -32,7 +32,7 @@
import android.util.FloatProperty;
import android.util.Log;
import android.view.InsetsFlags;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
@@ -434,9 +434,9 @@
@Override
public void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
- InsetsState requestedState, String packageName) {
- boolean isFullscreen = !requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
- || !requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ InsetsVisibilities requestedVisibilities, String packageName) {
+ boolean isFullscreen = !requestedVisibilities.getVisibility(ITYPE_STATUS_BAR)
+ || !requestedVisibilities.getVisibility(ITYPE_NAVIGATION_BAR);
if (mIsFullscreen != isFullscreen) {
mIsFullscreen = isFullscreen;
synchronized (mListeners) {
@@ -451,7 +451,7 @@
if (DEBUG_IMMERSIVE_APPS) {
boolean dim = (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0;
String behaviorName = ViewDebug.flagsToString(InsetsFlags.class, "behavior", behavior);
- String requestedVisibilityString = requestedState.toSourceVisibilityString();
+ String requestedVisibilityString = requestedVisibilities.toString();
if (requestedVisibilityString.isEmpty()) {
requestedVisibilityString = "none";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 0bbae2a..f0b2c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -19,7 +19,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -161,7 +161,7 @@
* Set the system bar attributes
*/
void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
- InsetsState requestedState, String packageName);
+ InsetsVisibilities requestedVisibilities, String packageName);
/**
* Set pulsing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 22bbb81b..d74297e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -29,7 +29,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.Utils
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
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..f2cf93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -24,12 +24,13 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
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;
import com.android.systemui.statusbar.MediaArtworkProcessor;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationListener;
@@ -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..c1f0578 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,7 +67,8 @@
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
) {
private var sbHeightPortrait = 0
@@ -84,18 +94,28 @@
// 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(object : StatusBarContentInsetsChangedListener {
+ override fun onStatusBarContentInsetsChanged() {
+ dlog("onStatusBarContentInsetsChanged: ")
+ setNewLayoutRects()
+ }
+ })
+
+ 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 +143,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 +245,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 +367,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 +399,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 +437,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 +477,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 +492,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 +538,30 @@
}
return -1
}
+
+ // 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 +582,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 +606,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 +629,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/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 71546ae..f2060b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -43,7 +43,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.settings.SecureSettings
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 1ab2a9e..a65f3d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -37,7 +37,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index b0a7767..a2c9ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -374,10 +374,6 @@
}
}
- fun getWakeUpHeight(): Float {
- return mStackScrollerController.wakeUpHeight
- }
-
private fun updateHideAmount() {
val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = min(1.0f - mVisibilityAmount, mDozeAmount)
@@ -395,16 +391,6 @@
}
}
- /**
- * Set the height how tall notifications are pulsing. This is only set whenever we are expanding
- * from a pulse and determines how much the notifications are expanded.
- */
- fun setPulseHeight(height: Float): Float {
- val overflow = mStackScrollerController.setPulseHeight(height)
- // no overflow for the bypass experience
- return if (bypassController.bypassEnabled) 0.0f else overflow
- }
-
override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
var animate = shouldAnimateVisibility()
if (!isHeadsUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8ae31cb..277b4ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -63,7 +63,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
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/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index d80cc08..25b2019 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -19,7 +19,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
index aec2647..518c3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.collection.inflation;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index db49e44..168e086 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -21,7 +21,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index f758114..55620b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -30,11 +30,11 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 32d90d3..c5899ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -20,7 +20,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
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/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 4559e13..45fd5ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -153,15 +153,6 @@
return mStackHeight;
}
- /**
- * @return Height of notifications panel, with the animation from pulseHeight accounted for.
- */
- // TODO(b/192348384): move this logic to getStackHeight, and remove this and getInnerHeight
- public float getPulseStackHeight() {
- float pulseHeight = Math.min(mPulseHeight, mStackHeight);
- return MathUtils.lerp(mStackHeight, pulseHeight, mDozeAmount);
- }
-
/** Tracks the state from AlertingNotificationManager#hasNotifications() */
private boolean mHasAlertEntries;
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..880e558 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
@@ -81,11 +81,8 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
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 +439,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 +453,7 @@
private float mLastSentExpandedHeight;
private boolean mWillExpand;
private int mGapHeight;
+ private boolean mIsRemoteInputActive;
/**
* The extra inset during the full shade transition
@@ -528,7 +525,6 @@
private NotificationEntry mTopHeadsUpEntry;
private long mNumHeadsUp;
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
- private final FeatureFlags mFeatureFlags;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mShouldUseSplitNotificationShade;
@@ -574,12 +570,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 +675,10 @@
mSectionsManager.reinflateViews(LayoutInflater.from(mContext));
}
+ public void setIsRemoteInputActive(boolean isActive) {
+ mIsRemoteInputActive = isActive;
+ }
+
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
@@ -690,11 +688,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;
@@ -5167,12 +5164,17 @@
* @return the overflow how much the height is further than he lowest notification
*/
public float setPulseHeight(float height) {
+ float overflow;
mAmbientState.setPulseHeight(height);
if (mKeyguardBypassEnabled) {
notifyAppearChangedListeners();
+ overflow = Math.max(0, height - getIntrinsicPadding());
+ } else {
+ overflow = Math.max(0, height
+ - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
}
requestChildrenUpdate();
- return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
+ return overflow;
}
public float getPulseHeight() {
@@ -5232,12 +5234,9 @@
public float calculateAppearFractionBypass() {
float pulseHeight = getPulseHeight();
- float wakeUpHeight = getWakeUpHeight();
- float dragDownAmount = pulseHeight - wakeUpHeight;
-
// The total distance required to fully reveal the header
float totalDistance = getIntrinsicPadding();
- return MathUtils.smoothStep(0, totalDistance, dragDownAmount);
+ return MathUtils.smoothStep(0, totalDistance, pulseHeight);
}
public void setController(
@@ -5369,10 +5368,6 @@
mFooterDismissListener = listener;
}
- public void setRemoteInputManager(NotificationRemoteInputManager remoteInputManager) {
- mRemoteInputManager = remoteInputManager;
- }
-
void setShadeController(ShadeController shadeController) {
mShadeController = shadeController;
}
@@ -5424,7 +5419,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..a865c3a 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
@@ -68,13 +68,13 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -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()) {
@@ -897,10 +903,6 @@
mView.setDozeAmount(amount);
}
- public float getWakeUpHeight() {
- return mView.getWakeUpHeight();
- }
-
public int getSpeedBumpIndex() {
return mView.getSpeedBumpIndex();
}
@@ -1470,6 +1472,11 @@
mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
}
+ /** */
+ public void setWillExpand(boolean willExpand) {
+ mView.setWillExpand(willExpand);
+ }
+
/**
* Set a listener to when scrolling changes.
*/
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..1b4ae9e 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();
@@ -441,19 +447,16 @@
// to shelf start, thereby hiding all notifications (except the first one, which
// we later unhide in updatePulsingState)
// TODO(b/192348384): merge InnerHeight with StackHeight
- final int stackBottom;
- if (ambientState.isBypassEnabled()) {
- // We want to use the stackHeight when pulse expanding, since the animation
- // isn't currently optimized if the pulseHeight is continuously changing
- // Let's improve this when we're merging the heights above
- stackBottom = ambientState.isPulseExpanding()
- ? (int) ambientState.getStackHeight()
- : ambientState.getInnerHeight();
- } else {
- stackBottom = !ambientState.isShadeExpanded() || ambientState.isDozing()
- ? ambientState.getInnerHeight()
- : (int) ambientState.getPulseStackHeight();
- }
+ // Note: Bypass pulse looks different, but when it is not expanding, we need
+ // to use the innerHeight which doesn't update continuously, otherwise we show
+ // more notifications than we should during this special transitional states.
+ boolean bypassPulseNotExpanding = ambientState.isBypassEnabled()
+ && ambientState.isOnKeyguard() && !ambientState.isPulseExpanding();
+ final int stackBottom =
+ !ambientState.isShadeExpanded() || ambientState.isDozing()
+ || bypassPulseNotExpanding
+ ? ambientState.getInnerHeight()
+ : (int) ambientState.getStackHeight();
final int shelfStart =
stackBottom - ambientState.getShelf().getIntrinsicHeight();
viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
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..1bd26c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -37,12 +37,11 @@
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.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -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,8 @@
@Override
public void onDestroyView() {
super.onDestroyView();
- Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
+ mStatusBarIconController.removeIconGroup(mDarkIconManager);
+ mAnimationScheduler.removeCallback(this);
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/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index b4f8126..908cd34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -29,9 +29,9 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6802472..a0af389 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -33,7 +33,7 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 91d503b..0a4e59c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
@@ -40,6 +41,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -81,6 +83,11 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.controls.ControlsServiceInfo;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.management.ControlsListingController;
+import com.android.systemui.controls.ui.ControlsActivity;
+import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.IntentButtonProvider;
@@ -98,6 +105,8 @@
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
+import java.util.List;
+
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -133,9 +142,12 @@
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mWalletButton;
+ private ImageView mControlsButton;
private boolean mHasCard = false;
private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
private QuickAccessWalletController mQuickAccessWalletController;
+ private ControlsComponent mControlsComponent;
+ private boolean mControlServicesAvailable = false;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
@@ -188,6 +200,19 @@
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private ControlsListingController.ControlsListingCallback mListingCallback =
+ new ControlsListingController.ControlsListingCallback() {
+ public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
+ boolean available = !serviceInfos.isEmpty();
+
+ if (available != mControlServicesAvailable) {
+ mControlServicesAvailable = available;
+ updateControlsVisibility();
+ updateAffordanceColors();
+ }
+ }
+ };
+
public KeyguardBottomAreaView(Context context) {
this(context, null);
}
@@ -253,6 +278,7 @@
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.left_button);
mWalletButton = findViewById(R.id.wallet_button);
+ mControlsButton = findViewById(R.id.controls_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
mIndicationText = findViewById(R.id.keyguard_indication_text);
mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
@@ -276,6 +302,7 @@
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
+ updateControlsVisibility();
}
/**
@@ -328,6 +355,11 @@
mQuickAccessWalletController.unregisterWalletChangeObservers(
WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
+
+ if (mControlsComponent != null) {
+ mControlsComponent.getControlsListingController().ifPresent(
+ c -> c.removeCallback(mListingCallback));
+ }
}
private void initAccessibility() {
@@ -369,13 +401,20 @@
updateLeftAffordanceIcon();
lp = mWalletButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
mWalletButton.setLayoutParams(lp);
+ lp = mControlsButton.getLayoutParams();
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
+ mControlsButton.setLayoutParams(lp);
+
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
+
updateWalletVisibility();
+ updateAffordanceColors();
}
private void updateRightAffordanceIcon() {
@@ -454,22 +493,38 @@
|| !mQuickAccessWalletController.isWalletEnabled()
|| !mHasCard) {
mWalletButton.setVisibility(GONE);
- mIndicationArea.setPadding(0, 0, 0, 0);
- } else {
- Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
- if (tileIcon != null) {
- mWalletButton.setImageDrawable(tileIcon);
+
+ if (mControlsButton.getVisibility() == GONE) {
+ mIndicationArea.setPadding(0, 0, 0, 0);
}
- mWalletButton.getDrawable().setTint(
- Utils.getColorAttr(
- mContext,
- com.android.internal.R.attr.textColorPrimary).getDefaultColor());
+ } else {
mWalletButton.setVisibility(VISIBLE);
mWalletButton.setOnClickListener(this::onWalletClick);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
}
}
+ private void updateControlsVisibility() {
+ if (mControlsComponent == null) return;
+
+ boolean hasFavorites = mControlsComponent.getControlsController()
+ .map(c -> c.getFavorites().size() > 0)
+ .orElse(false);
+ if (mDozing
+ || !hasFavorites
+ || !mControlServicesAvailable
+ || mControlsComponent.getVisibility() != AVAILABLE) {
+ mControlsButton.setVisibility(GONE);
+ if (mWalletButton.getVisibility() == GONE) {
+ mIndicationArea.setPadding(0, 0, 0, 0);
+ }
+ } else {
+ mControlsButton.setVisibility(VISIBLE);
+ mControlsButton.setOnClickListener(this::onControlsClick);
+ mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
+ }
+ }
+
public boolean isLeftVoiceAssist() {
return mLeftIsVoiceAssist;
}
@@ -751,6 +806,9 @@
if (mWalletButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mWalletButton, delay);
}
+ if (mControlsButton.getVisibility() == View.VISIBLE) {
+ startFinishDozeAnimationElement(mControlsButton, delay);
+ }
if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mLeftAffordanceView, delay);
delay += DOZE_ANIMATION_STAGGER_DELAY;
@@ -824,6 +882,7 @@
updateCameraVisibility();
updateLeftAffordanceIcon();
updateWalletVisibility();
+ updateControlsVisibility();
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
@@ -857,6 +916,7 @@
mRightAffordanceView.setAlpha(alpha);
mIndicationArea.setAlpha(alpha);
mWalletButton.setAlpha(alpha);
+ mControlsButton.setAlpha(alpha);
}
private class DefaultLeftButton implements IntentButton {
@@ -950,6 +1010,32 @@
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
+ updateAffordanceColors();
+ }
+
+ private void updateAffordanceColors() {
+ int iconColor = Utils.getColorAttrDefaultColor(
+ mContext,
+ com.android.internal.R.attr.textColorPrimary);
+ mWalletButton.getDrawable().setTint(iconColor);
+ mControlsButton.getDrawable().setTint(iconColor);
+
+ ColorStateList bgColor = Utils.getColorAttr(
+ mContext,
+ com.android.internal.R.attr.colorSurface);
+ mWalletButton.setBackgroundTintList(bgColor);
+ mControlsButton.setBackgroundTintList(bgColor);
+ }
+
+ /**
+ * Initialize controls via the ControlsComponent
+ */
+ public void initControls(ControlsComponent controlsComponent) {
+ mControlsComponent = controlsComponent;
+ mControlsComponent.getControlsListingController().ifPresent(
+ c -> c.addCallback(mListingCallback));
+
+ updateAffordanceColors();
}
private void onWalletClick(View v) {
@@ -974,19 +1060,41 @@
}
}
+ private void onControlsClick(View v) {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+
+ Intent intent = new Intent(mContext, ControlsActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
+
+ if (mControlsComponent.getVisibility() == AVAILABLE) {
+ mContext.startActivity(intent);
+ } else {
+ mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */);
+ }
+ }
+
private class WalletCardRetriever implements
QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
@Override
public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
mHasCard = !response.getWalletCards().isEmpty();
+ Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
+ if (tileIcon != null) {
+ mWalletButton.setImageDrawable(tileIcon);
+ }
updateWalletVisibility();
+ updateAffordanceColors();
}
@Override
public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
mHasCard = false;
updateWalletVisibility();
+ updateAffordanceColors();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 6caeba2..c0600b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -232,6 +232,7 @@
pw.println(" launchingAffordance: $launchingAffordance")
pw.println(" qSExpanded: $qSExpanded")
pw.println(" hasFaceFeature: $hasFaceFeature")
+ pw.println(" userHasDeviceEntryIntent: $userHasDeviceEntryIntent")
}
/** Registers a listener for bypass state changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index ad4213d..f77c052 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -211,7 +211,7 @@
private int getStackScrollerPadding(int clockYPosition) {
if (mBypassEnabled) {
- return mUnlockedStackScrollerPadding;
+ return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
return clockYPosition;
} else {
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/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e272d27..a73cad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -18,10 +18,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
-import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
@@ -45,36 +42,18 @@
import android.widget.TextView;
import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
-import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* The header group on Keyguard.
*/
-public class KeyguardStatusBarView extends RelativeLayout implements
- BatteryStateChangeCallback,
- OnUserInfoChangedListener,
- ConfigurationListener,
- SystemStatusAnimationCallback {
+public class KeyguardStatusBarView extends RelativeLayout {
private static final int LAYOUT_NONE = 0;
private static final int LAYOUT_CUTOUT = 1;
@@ -84,30 +63,23 @@
private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
- private boolean mBatteryListening;
private TextView mCarrierLabel;
private ImageView mMultiUserAvatar;
private BatteryMeterView mBatteryView;
private StatusIconContainer mStatusIconContainer;
- private BatteryController mBatteryController;
private boolean mKeyguardUserSwitcherEnabled;
private final UserManager mUserManager;
private int mSystemIconsSwitcherHiddenExpandedMargin;
private int mSystemIconsBaseMargin;
private View mSystemIconsContainer;
- private TintedIconManager mIconManager;
- private List<String> mBlockedIcons = new ArrayList<>();
private View mCutoutSpace;
private ViewGroup mStatusIconArea;
private int mLayoutState = LAYOUT_NONE;
- private SystemStatusAnimationScheduler mAnimationScheduler;
- private FeatureFlags mFeatureFlags;
-
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
*/
@@ -141,10 +113,6 @@
mStatusIconContainer = findViewById(R.id.statusIcons);
loadDimens();
- loadBlockList();
- mBatteryController = Dependency.get(BatteryController.class);
- mAnimationScheduler = Dependency.get(SystemStatusAnimationScheduler.class);
- mFeatureFlags = Dependency.get(FeatureFlags.class);
}
@Override
@@ -190,7 +158,7 @@
setLayoutParams(lp);
}
- private void loadDimens() {
+ void loadDimens() {
Resources res = getResources();
mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
R.dimen.system_icons_switcher_hidden_expanded_margin);
@@ -204,14 +172,6 @@
R.dimen.rounded_corner_content_padding);
}
- // Set hidden status bar items
- private void loadBlockList() {
- Resources r = getResources();
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_volume));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_call_strength));
- }
-
private void updateVisibilities() {
if (mMultiUserAvatar.getParent() != mStatusIconArea
&& !mKeyguardUserSwitcherEnabled) {
@@ -348,59 +308,19 @@
return true;
}
- public void setListening(boolean listening) {
- if (listening == mBatteryListening) {
- return;
- }
- mBatteryListening = listening;
- if (mBatteryListening) {
- mBatteryController.addCallback(this);
- } else {
- mBatteryController.removeCallback(this);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- UserInfoController userInfoController = Dependency.get(UserInfoController.class);
- userInfoController.addCallback(this);
- userInfoController.reloadUserInfo();
- Dependency.get(ConfigurationController.class).addCallback(this);
- mIconManager = new TintedIconManager(findViewById(R.id.statusIcons), mFeatureFlags);
- mIconManager.setBlockList(mBlockedIcons);
- Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
- mAnimationScheduler.addCallback(this);
- onThemeChanged();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(UserInfoController.class).removeCallback(this);
- Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
- Dependency.get(ConfigurationController.class).removeCallback(this);
- mAnimationScheduler.removeCallback(this);
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onUserInfoChanged(Drawable picture) {
mMultiUserAvatar.setImageDrawable(picture);
}
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onBatteryLevelChanged(boolean charging) {
if (mBatteryCharging != charging) {
mBatteryCharging = charging;
updateVisibilities();
}
}
- @Override
- public void onPowerSaveChanged(boolean isPowerSave) {
- // could not care less
- }
-
public void setKeyguardUserSwitcherEnabled(boolean enabled) {
mKeyguardUserSwitcherEnabled = enabled;
}
@@ -467,28 +387,20 @@
return false;
}
- public void onThemeChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onThemeChanged(StatusBarIconController.TintedIconManager iconManager) {
mBatteryView.setColorsFromContext(mContext);
- updateIconsAndTextColors();
- // Reload user avatar
- ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
- .onDensityOrFontScaleChanged();
+ updateIconsAndTextColors(iconManager);
}
- @Override
- public void onDensityOrFontScaleChanged() {
- loadDimens();
- }
-
- @Override
- public void onOverlayChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onOverlayChanged() {
mCarrierLabel.setTextAppearance(
Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
- onThemeChanged();
mBatteryView.updatePercentView();
}
- private void updateIconsAndTextColors() {
+ private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) {
@ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
@ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
@@ -496,8 +408,8 @@
R.color.light_mode_icon_color_single_tone);
float intensity = textColor == Color.WHITE ? 0 : 1;
mCarrierLabel.setTextColor(iconColor);
- if (mIconManager != null) {
- mIconManager.setTint(iconColor);
+ if (iconManager != null) {
+ iconManager.setTint(iconColor);
}
applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
@@ -522,10 +434,10 @@
}
}
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusBarView:");
pw.println(" mBatteryCharging: " + mBatteryCharging);
- pw.println(" mBatteryListening: " + mBatteryListening);
pw.println(" mLayoutState: " + mLayoutState);
pw.println(" mKeyguardUserSwitcherEnabled: " + mKeyguardUserSwitcherEnabled);
if (mBatteryView != null) {
@@ -533,19 +445,16 @@
}
}
- /** SystemStatusAnimationCallback */
- @Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT) {
+ void onSystemChromeAnimationStart(boolean isAnimatingOut) {
+ if (isAnimatingOut) {
mSystemIconsContainer.setVisibility(View.VISIBLE);
mSystemIconsContainer.setAlpha(0f);
}
}
- @Override
- public void onSystemChromeAnimationEnd() {
+ void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
// Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
+ if (isAnimatingIn) {
mSystemIconsContainer.setVisibility(View.INVISIBLE);
mSystemIconsContainer.setAlpha(0f);
} else {
@@ -554,9 +463,8 @@
}
}
- @Override
- public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
- mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
+ void onSystemChromeAnimationUpdate(float animatedValue) {
+ mSystemIconsContainer.setAlpha(animatedValue);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 377fb92..bfadc3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,33 +16,184 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
+
+import android.animation.ValueAnimator;
+import android.content.res.Resources;
+
+import androidx.annotation.NonNull;
+
import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.ViewController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import javax.inject.Inject;
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private final CarrierTextController mCarrierTextController;
+ private final ConfigurationController mConfigurationController;
+ private final SystemStatusAnimationScheduler mAnimationScheduler;
+ private final BatteryController mBatteryController;
+ private final UserInfoController mUserInfoController;
+ private final StatusBarIconController mStatusBarIconController;
+ private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+ private final BatteryMeterViewController mBatteryMeterViewController;
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.loadDimens();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ mView.onOverlayChanged();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ }
+ };
+
+ private final SystemStatusAnimationCallback mAnimationCallback =
+ new SystemStatusAnimationCallback() {
+ @Override
+ public void onSystemChromeAnimationStart() {
+ mView.onSystemChromeAnimationStart(
+ mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ }
+
+ @Override
+ public void onSystemChromeAnimationEnd() {
+ mView.onSystemChromeAnimationEnd(
+ mAnimationScheduler.getAnimationState() == ANIMATING_IN);
+ }
+
+ @Override
+ public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
+ mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ }
+ };
+
+ private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
+ new BatteryController.BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ mView.onBatteryLevelChanged(charging);
+ }
+ };
+
+ private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
+ (name, picture, userAccount) -> mView.onUserInfoChanged(picture);
+
+ private final List<String> mBlockedIcons;
+
+ private boolean mBatteryListening;
+ private StatusBarIconController.TintedIconManager mTintedIconManager;
@Inject
public KeyguardStatusBarViewController(
- KeyguardStatusBarView view, CarrierTextController carrierTextController) {
+ KeyguardStatusBarView view,
+ CarrierTextController carrierTextController,
+ ConfigurationController configurationController,
+ SystemStatusAnimationScheduler animationScheduler,
+ BatteryController batteryController,
+ UserInfoController userInfoController,
+ StatusBarIconController statusBarIconController,
+ StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
+ BatteryMeterViewController batteryMeterViewController) {
super(view);
mCarrierTextController = carrierTextController;
+ mConfigurationController = configurationController;
+ mAnimationScheduler = animationScheduler;
+ mBatteryController = batteryController;
+ mUserInfoController = userInfoController;
+ mStatusBarIconController = statusBarIconController;
+ mTintedIconManagerFactory = tintedIconManagerFactory;
+ mBatteryMeterViewController = batteryMeterViewController;
+
+ Resources r = getResources();
+ mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
+ r.getString(com.android.internal.R.string.status_bar_volume),
+ r.getString(com.android.internal.R.string.status_bar_alarm_clock),
+ r.getString(com.android.internal.R.string.status_bar_call_strength)));
}
@Override
protected void onInit() {
super.onInit();
mCarrierTextController.init();
+ mBatteryMeterViewController.init();
}
@Override
protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ mAnimationScheduler.addCallback(mAnimationCallback);
+ mUserInfoController.addCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager == null) {
+ mTintedIconManager =
+ mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
+ mTintedIconManager.setBlockList(mBlockedIcons);
+ mStatusBarIconController.addIconGroup(mTintedIconManager);
+ }
+ onThemeChanged();
}
@Override
protected void onViewDetached() {
+ // Don't receive future #onViewAttached calls so that we don't accidentally have two
+ // controllers registered for the same view.
+ // TODO(b/194181195): This shouldn't be necessary.
+ destroy();
+
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mAnimationScheduler.removeCallback(mAnimationCallback);
+ mUserInfoController.removeCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager != null) {
+ mStatusBarIconController.removeIconGroup(mTintedIconManager);
+ }
+ }
+
+ /** Should be called when the theme changes. */
+ public void onThemeChanged() {
+ mView.onThemeChanged(mTintedIconManager);
+ }
+
+ /** Sets whether this controller should listen to battery updates. */
+ public void setBatteryListening(boolean listening) {
+ if (listening == mBatteryListening) {
+ return;
+ }
+ mBatteryListening = listening;
+ if (mBatteryListening) {
+ mBatteryController.addCallback(mBatteryStateChangeCallback);
+ } else {
+ mBatteryController.removeCallback(mBatteryStateChangeCallback);
+ }
+ }
+
+ /** */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyguardStatusBarView:");
+ pw.println(" mBatteryListening: " + mBatteryListening);
+ mView.dump(fd, pw, args);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index c213707..3f33281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -21,7 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -150,7 +150,8 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index cfe95e0..6516abd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -165,14 +165,14 @@
* Called by the Keyguard*ViewController whose view contains the aod icons.
*/
public void setupAodIcons(@NonNull NotificationIconContainer aodIcons) {
- boolean changed = mAodIcons != null;
+ boolean changed = mAodIcons != null && aodIcons != mAodIcons;
if (changed) {
mAodIcons.setAnimationsEnabled(false);
mAodIcons.removeAllViews();
}
mAodIcons = aodIcons;
mAodIcons.setOnLockScreen(true);
- updateAodIconsVisibility(false /* animate */);
+ updateAodIconsVisibility(false /* animate */, changed);
updateAnimations();
if (changed) {
updateAodNotificationIcons();
@@ -587,7 +587,7 @@
@Override
public void onStateChanged(int newState) {
- updateAodIconsVisibility(false /* animate */);
+ updateAodIconsVisibility(false /* animate */, false /* force */);
updateAnimations();
}
@@ -663,18 +663,18 @@
// since otherwise the unhide animation overlaps
animate &= fullyHidden;
}
- updateAodIconsVisibility(animate);
+ updateAodIconsVisibility(animate, false /* force */);
updateAodNotificationIcons();
}
@Override
public void onPulseExpansionChanged(boolean expandingChanged) {
if (expandingChanged) {
- updateAodIconsVisibility(true /* animate */);
+ updateAodIconsVisibility(true /* animate */, false /* force */);
}
}
- private void updateAodIconsVisibility(boolean animate) {
+ private void updateAodIconsVisibility(boolean animate, boolean forceUpdate) {
if (mAodIcons == null) {
return;
}
@@ -688,10 +688,11 @@
&& !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
visible = false;
}
- if (visible && mWakeUpCoordinator.isPulseExpanding()) {
+ if (visible && mWakeUpCoordinator.isPulseExpanding()
+ && !mBypassController.getBypassEnabled()) {
visible = false;
}
- if (mAodIconsVisible != visible) {
+ if (mAodIconsVisible != visible || forceUpdate) {
mAodIconsVisible = visible;
mAodIcons.animate().cancel();
if (animate) {
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..3e39b46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -80,6 +80,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,11 +105,20 @@
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.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.idle.IdleHostView;
+import com.android.systemui.idle.IdleHostViewController;
+import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -123,7 +133,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 +182,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,20 +324,23 @@
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 IdleViewComponent.Factory mIdleViewComponentFactory;
private final QSDetailDisplayer mQSDetailDisplayer;
private final FragmentService mFragmentService;
- private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
private final QuickAccessWalletController mQuickAccessWalletController;
+ private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
@@ -348,11 +361,15 @@
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
- private KeyguardStatusBarViewController mKeyguarStatusBarViewController;
+ private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
private ViewGroup mBigClockContainer;
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
+ @Nullable
+ private CommunalHostViewController mCommunalViewController;
private KeyguardStatusViewController mKeyguardStatusViewController;
+ @Nullable
+ private IdleHostViewController mIdleHostViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private boolean mAnimateNextPositionUpdate;
@@ -363,6 +380,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 +529,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;
@@ -616,6 +653,11 @@
* Is the current animator resetting the qs translation.
*/
private boolean mIsQsTranslationResetAnimator;
+
+ /**
+ * Is the current animator resetting the pulse expansion after a drag down
+ */
+ private boolean mIsPulseExpansionResetAnimator;
private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private final Region mQsInterceptRegion = new Region();
@@ -634,6 +676,9 @@
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private int mQsClipTop;
+ private int mQsClipBottom;
+ private boolean mQsVisible;
private final ContentResolver mContentResolver;
private final Executor mUiExecutor;
@@ -692,7 +737,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 +752,8 @@
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
+ CommunalViewComponent.Factory communalViewComponentFactory,
+ IdleViewComponent.Factory idleViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
QSDetailDisplayer qsDetailDisplayer,
NotificationGroupManagerLegacy groupManager,
@@ -717,7 +765,6 @@
NotificationShadeDepthController notificationShadeDepthController,
AmbientState ambientState,
LockIconViewController lockIconViewController,
- FeatureFlags featureFlags,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
TapAgainViewController tapAgainViewController,
@@ -730,7 +777,8 @@
SecureSettings secureSettings,
SplitShadeHeaderController splitShadeHeaderController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- NotificationRemoteInputManager remoteInputManager) {
+ NotificationRemoteInputManager remoteInputManager,
+ ControlsComponent controlsComponent) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
@@ -740,6 +788,7 @@
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
mQuickAccessWalletController = quickAccessWalletController;
+ mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -749,10 +798,11 @@
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
+ mCommunalViewComponentFactory = communalViewComponentFactory;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
+ mIdleViewComponentFactory = idleViewComponentFactory;
mDepthController = notificationShadeDepthController;
- mFeatureFlags = featureFlags;
mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
@@ -760,7 +810,7 @@
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
- Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
+ Utils.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG);
mSplitShadeHeaderController = splitShadeHeaderController;
mLayoutInflater = layoutInflater;
@@ -792,6 +842,7 @@
mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
+ mCommunalSourceMonitor = communalSourceMonitor;
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
KeyguardStateController.Callback
keyguardMonitorCallback =
@@ -853,6 +904,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 +923,9 @@
mView.findViewById(R.id.keyguard_status_view),
userAvatarView,
mKeyguardStatusBar,
- keyguardUserSwitcherView);
+ keyguardUserSwitcherView,
+ mCommunalView,
+ mView.findViewById(R.id.idle_host_view));
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
@@ -894,14 +948,7 @@
mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController);
mQsFrame = mView.findViewById(R.id.qs_frame);
- mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController,
- amount -> {
- float progress = amount / mView.getHeight();
- float overstretch = Interpolators.getOvershootInterpolation(progress,
- (float) mMaxOverscrollAmountForPulse / mView.getHeight(),
- 0.2f);
- setOverStrechAmount(overstretch);
- });
+ mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController);
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
@@ -913,7 +960,6 @@
if (mKeyguardBypassController.getBypassEnabled()) {
// Position the notifications while dragging down while pulsing
requestScrollerTopPaddingUpdate(false /* animate */);
- updateQSPulseExpansion();
}
}
});
@@ -951,8 +997,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,18 +1017,36 @@
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
UserAvatarView userAvatarView,
KeyguardStatusBarView keyguardStatusBarView,
- KeyguardUserSwitcherView keyguardUserSwitcherView) {
+ KeyguardUserSwitcherView keyguardUserSwitcherView,
+ CommunalHostView communalView,
+ IdleHostView idleHostView) {
// Re-associate the KeyguardStatusViewController
KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
mKeyguardStatusViewController.init();
+ IdleViewComponent idleViewComponent = mIdleViewComponentFactory.build(idleHostView);
+ mIdleHostViewController = idleViewComponent.getIdleHostViewController();
+ mIdleHostViewController.init();
+
KeyguardStatusBarViewComponent statusBarViewComponent =
mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
- mKeyguarStatusBarViewController =
+ if (mKeyguardStatusBarViewController != null) {
+ // TODO(b/194181195): This shouldn't be necessary.
+ mKeyguardStatusBarViewController.onViewDetached();
+ }
+ mKeyguardStatusBarViewController =
statusBarViewComponent.getKeyguardStatusBarViewController();
- mKeyguarStatusBarViewController.init();
+ mKeyguardStatusBarViewController.init();
+
+ if (communalView != null) {
+ CommunalViewComponent communalViewComponent =
+ mCommunalViewComponentFactory.build(communalView);
+ mCommunalViewController =
+ communalViewComponent.getCommunalHostViewController();
+ mCommunalViewController.init();
+ }
if (mKeyguardUserSwitcherController != null) {
// Try to close the switcher so that callbacks are triggered if necessary.
@@ -1037,7 +1099,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 +1113,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 +1208,8 @@
mBigClockContainer.removeAllViews();
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- mKeyguardStatusBar, keyguardUserSwitcherView);
+ mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView,
+ mView.findViewById(R.id.idle_host_view));
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1161,10 +1225,6 @@
mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.onThemeChanged();
- }
-
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
mBarState,
false,
@@ -1199,6 +1259,7 @@
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
+ mKeyguardBottomArea.initControls(mControlsComponent);
}
private void updateMaxDisplayedNotifications(boolean recompute) {
@@ -1373,7 +1434,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 +1449,7 @@
transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
TransitionManager.beginDelayedTransition(mNotificationContainerParent, transition);
}
+
constraintSet.applyTo(mNotificationContainerParent);
}
}
@@ -1394,14 +1458,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 +1683,7 @@
private boolean isQsExpansionEnabled() {
return mQsExpansionEnabledPolicy && mQsExpansionEnabledAmbient
- && !mRemoteInputManager.getController().isRemoteInputActive();
+ && !mRemoteInputManager.isRemoteInputActive();
}
public void expandWithQs() {
@@ -2293,7 +2361,7 @@
}
}
- protected void updateQsExpansion() {
+ private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
@@ -2353,9 +2421,20 @@
top = mTransitionToFullShadeQSPosition;
} else {
final float notificationTop = getQSEdgePosition();
- top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
- : notificationTop);
+ if (isOnKeyguard()) {
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ // When bypassing on the keyguard, let's use the panel bottom.
+ // this should go away once we unify the stackY position and don't have
+ // to do this min anymore below.
+ top = qsPanelBottomY;
+ } else {
+ top = (int) Math.min(qsPanelBottomY, notificationTop);
+ }
+ } else {
+ top = (int) notificationTop;
+ }
}
+ top += mOverStretchAmount;
bottom = getView().getBottom();
// notification bounds should take full screen width regardless of insets
left = 0;
@@ -2386,6 +2465,9 @@
final int startTop = mKeyguardStatusAreaClipBounds.top;
final int startRight = mKeyguardStatusAreaClipBounds.right;
final int startBottom = mKeyguardStatusAreaClipBounds.bottom;
+ if (mQsClippingAnimation != null) {
+ mQsClippingAnimation.cancel();
+ }
mQsClippingAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
mQsClippingAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mQsClippingAnimation.setDuration(mNotificationBoundsAnimationDuration);
@@ -2408,6 +2490,7 @@
public void onAnimationEnd(Animator animation) {
mQsClippingAnimation = null;
mIsQsTranslationResetAnimator = false;
+ mIsPulseExpansionResetAnimator = false;
}
});
mQsClippingAnimation.start();
@@ -2433,16 +2516,27 @@
}
if (mQs != null) {
float qsTranslation = 0;
- if (mTransitioningToFullShadeProgress > 0.0f || (mQsClippingAnimation != null
- && mIsQsTranslationResetAnimator)) {
- qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
+ boolean pulseExpanding = mPulseExpansionHandler.isExpanding();
+ if (mTransitioningToFullShadeProgress > 0.0f || pulseExpanding
+ || (mQsClippingAnimation != null
+ && (mIsQsTranslationResetAnimator || mIsPulseExpansionResetAnimator))) {
+ if (pulseExpanding || mIsPulseExpansionResetAnimator) {
+ // qsTranslation should only be positive during pulse expansion because it's
+ // already translating in from the top
+ qsTranslation = Math.max(0, (top - mQs.getHeader().getHeight()) / 2.0f);
+ } else {
+ qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
+ }
}
mQsTranslationForFullShadeTransition = qsTranslation;
updateQsFrameTranslation();
float currentTranslation = mQsFrame.getTranslationY();
- mQs.setFancyClipping((
- int) (top - currentTranslation),
- (int) (bottom - currentTranslation),
+ mQsClipTop = (int) (top - currentTranslation);
+ mQsClipBottom = (int) (bottom - currentTranslation);
+ mQsVisible = qsVisible;
+ mQs.setFancyClipping(
+ mQsClipTop,
+ mQsClipBottom,
radius, qsVisible
&& !mShouldUseSplitNotificationShade);
}
@@ -2513,7 +2607,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 +2620,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;
}
}
@@ -2564,14 +2658,6 @@
}
}
- private void updateQSPulseExpansion() {
- if (mQs != null) {
- mQs.setPulseExpanding(
- mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()
- && mNotificationStackScrollLayoutController.isPulseExpanding());
- }
- }
-
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
* shade. 0.0f means we're not transitioning yet.
@@ -2623,6 +2709,15 @@
}
/**
+ * Notify the panel that the pulse expansion has finished and that we're going to the full
+ * shade
+ */
+ public void onPulseExpansionFinished() {
+ animateNextNotificationBounds(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE, 0);
+ mIsPulseExpansionResetAnimator = true;
+ }
+
+ /**
* Set the alpha of the keyguard elements which only show on the lockscreen, but not in
* shade locked / shade. This is used when dragging down to the full shade.
*/
@@ -2915,10 +3010,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();
@@ -2983,19 +3074,7 @@
startHeight = -mQsExpansionHeight * QS_PARALLAX_AMOUNT;
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
- if (mNotificationStackScrollLayoutController.isPulseExpanding()) {
- if (!mPulseExpansionHandler.isExpanding()
- && !mPulseExpansionHandler.getLeavingLockscreen()) {
- // If we aborted the expansion we need to make sure the header doesn't reappear
- // again after the header has animated away
- appearAmount = 0;
- } else {
- appearAmount = mNotificationStackScrollLayoutController
- .calculateAppearFractionBypass();
- }
- } else {
- appearAmount = 0.0f;
- }
+ appearAmount = mNotificationStackScrollLayoutController.calculateAppearFractionBypass();
startHeight = -mQs.getQsMinExpansionHeight();
}
float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount));
@@ -3143,7 +3222,7 @@
}
private void setListening(boolean listening) {
- mKeyguardStatusBar.setListening(listening);
+ mKeyguardStatusBarViewController.setBatteryListening(listening);
if (mQs == null) return;
mQs.setListening(listening);
}
@@ -3295,7 +3374,10 @@
switch (mBarState) {
case KEYGUARD:
if (!mDozingOnDown) {
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mUpdateMonitor.isFaceEnrolled()
+ && !mUpdateMonitor.isFaceDetectionRunning()
+ && !mUpdateMonitor.getUserCanSkipBouncer(
+ KeyguardUpdateMonitor.getCurrentUser())) {
mUpdateMonitor.requestFaceAuth(true);
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
@@ -3598,7 +3680,6 @@
mQs.setPanelView(mHeightListener);
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(isQsExpansionEnabled());
- updateQSPulseExpansion();
mQs.setOverscrolling(mStackScrollerOverscrolling);
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
@@ -3695,8 +3776,6 @@
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mLockIconViewController.setAmbientIndicationBottomPadding(
- mAmbientIndicationBottomPadding);
updateMaxDisplayedNotifications(true);
}
}
@@ -3789,9 +3868,12 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
- pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.dump(fd, pw, args);
+ pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect()
+ + " applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom
+ + ") qsVisible(" + mQsVisible
+ );
+ if (mKeyguardStatusBarViewController != null) {
+ mKeyguardStatusBarViewController.dump(fd, pw, args);
}
}
@@ -4361,8 +4443,7 @@
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
- mNotificationStackScrollLayoutController.setMaxTopPadding(
- mQsMaxExpansionHeight + mQsNotificationTopPadding);
+ mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
}
}
@@ -4480,7 +4561,6 @@
updateMaxDisplayedNotifications(false);
// The update needs to happen after the headerSlide in above, otherwise the translation
// would reset
- updateQSPulseExpansion();
maybeAnimateBottomAreaAlpha();
resetHorizontalPanelPosition();
updateQsState();
@@ -4513,11 +4593,34 @@
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.
*/
public void setOverStrechAmount(float amount) {
- mOverStretchAmount = amount;
+ float progress = amount / mView.getHeight();
+ float overstretch = Interpolators.getOvershootInterpolation(progress);
+ mOverStretchAmount = overstretch * mMaxOverscrollAmountForPulse;
positionClockAndNotifications(true /* forceUpdate */);
}
@@ -4529,6 +4632,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 +4650,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 +4678,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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 44ed279..43a8630 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -136,12 +136,6 @@
public static final float BUSY_SCRIM_ALPHA = 1f;
/**
- * The default scrim under the expanded bubble stack.
- * This should not be lower than 0.54, otherwise we won't pass GAR.
- */
- public static final float BUBBLE_SCRIM_ALPHA = 0.6f;
-
- /**
* Scrim opacity that can have text on top.
*/
public static final float GAR_SCRIM_ALPHA = 0.6f;
@@ -156,8 +150,6 @@
private ScrimView mScrimInFront;
private ScrimView mNotificationsScrim;
private ScrimView mScrimBehind;
- @Nullable
- private ScrimView mScrimForBubble;
private Runnable mScrimBehindChangeRunnable;
@@ -195,12 +187,10 @@
private float mInFrontAlpha = NOT_INITIALIZED;
private float mBehindAlpha = NOT_INITIALIZED;
private float mNotificationsAlpha = NOT_INITIALIZED;
- private float mBubbleAlpha = NOT_INITIALIZED;
private int mInFrontTint;
private int mBehindTint;
private int mNotificationsTint;
- private int mBubbleTint;
private boolean mWallpaperVisibilityTimedOut;
private int mScrimsVisibility;
@@ -229,7 +219,6 @@
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
- ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA);
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -276,11 +265,10 @@
* Attach the controller to the supplied views.
*/
public void attachViews(ScrimView behindScrim, ScrimView notificationsScrim,
- ScrimView scrimInFront, @Nullable ScrimView scrimForBubble) {
+ ScrimView scrimInFront) {
mNotificationsScrim = notificationsScrim;
mScrimBehind = behindScrim;
mScrimInFront = scrimInFront;
- mScrimForBubble = scrimForBubble;
updateThemeColors();
behindScrim.enableBottomEdgeConcave(mClipsQsScrim);
@@ -293,8 +281,7 @@
final ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
- states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
- mDockManager);
+ states[i].init(mScrimInFront, mScrimBehind, mDozeParameters, mDockManager);
states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
states[i].setDefaultScrimAlpha(mDefaultScrimAlpha);
}
@@ -302,9 +289,6 @@
mScrimBehind.setDefaultFocusHighlightEnabled(false);
mNotificationsScrim.setDefaultFocusHighlightEnabled(false);
mScrimInFront.setDefaultFocusHighlightEnabled(false);
- if (mScrimForBubble != null) {
- mScrimForBubble.setDefaultFocusHighlightEnabled(false);
- }
updateScrims();
mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
}
@@ -496,8 +480,7 @@
boolean relevantState = (mState == ScrimState.UNLOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.SHADE_LOCKED
- || mState == ScrimState.PULSING
- || mState == ScrimState.BUBBLE_EXPANDED);
+ || mState == ScrimState.PULSING);
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
@@ -564,8 +547,7 @@
mQsBottomVisible = qsBottomVisible;
boolean relevantState = (mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.KEYGUARD
- || mState == ScrimState.PULSING
- || mState == ScrimState.BUBBLE_EXPANDED);
+ || mState == ScrimState.PULSING);
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
@@ -627,11 +609,9 @@
mInFrontTint = mState.getFrontTint();
mBehindTint = mState.getBehindTint();
mNotificationsTint = mState.getNotifTint();
- mBubbleTint = mState.getBubbleTint();
mInFrontAlpha = mState.getFrontAlpha();
mBehindAlpha = mState.getBehindAlpha();
- mBubbleAlpha = mState.getBubbleAlpha();
mNotificationsAlpha = mState.getNotifAlpha();
assertAlphasValid();
@@ -640,7 +620,7 @@
return;
}
- if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
+ if (mState == ScrimState.UNLOCKED) {
// Darken scrim as you pull down the shade when unlocked, unless the shade is expanding
// because we're doing the screen off animation.
if (!mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
@@ -744,7 +724,6 @@
setOrAdaptCurrentAnimation(mScrimBehind);
setOrAdaptCurrentAnimation(mNotificationsScrim);
setOrAdaptCurrentAnimation(mScrimInFront);
- setOrAdaptCurrentAnimation(mScrimForBubble);
dispatchBackScrimState(mScrimBehind.getViewAlpha());
// Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
@@ -852,11 +831,6 @@
setScrimAlpha(mScrimBehind, mBehindAlpha);
setScrimAlpha(mNotificationsScrim, mNotificationsAlpha);
- if (mScrimForBubble != null) {
- boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen;
- mScrimForBubble.setColors(mColors, animateScrimForBubble);
- setScrimAlpha(mScrimForBubble, mBubbleAlpha);
- }
// The animation could have all already finished, let's call onFinished just in case
onFinished(mState);
dispatchScrimsVisible();
@@ -909,8 +883,6 @@
return "behind_scrim";
} else if (scrim == mNotificationsScrim) {
return "notifications_scrim";
- } else if (scrim == mScrimForBubble) {
- return "bubble_scrim";
}
return "unknown_scrim";
}
@@ -983,8 +955,6 @@
return mBehindAlpha;
} else if (scrim == mNotificationsScrim) {
return mNotificationsAlpha;
- } else if (scrim == mScrimForBubble) {
- return mBubbleAlpha;
} else {
throw new IllegalArgumentException("Unknown scrim view");
}
@@ -997,8 +967,6 @@
return mBehindTint;
} else if (scrim == mNotificationsScrim) {
return mNotificationsTint;
- } else if (scrim == mScrimForBubble) {
- return mBubbleTint;
} else {
throw new IllegalArgumentException("Unknown scrim view");
}
@@ -1030,8 +998,7 @@
}
if (isAnimating(mScrimBehind)
|| isAnimating(mNotificationsScrim)
- || isAnimating(mScrimInFront)
- || isAnimating(mScrimForBubble)) {
+ || isAnimating(mScrimInFront)) {
if (callback != null && callback != mCallback) {
// Since we only notify the callback that we're finished once everything has
// finished, we need to make sure that any changing callbacks are also invoked
@@ -1058,13 +1025,9 @@
mInFrontTint = Color.TRANSPARENT;
mBehindTint = mState.getBehindTint();
mNotificationsTint = mState.getNotifTint();
- mBubbleTint = Color.TRANSPARENT;
updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
updateScrimColor(mNotificationsScrim, mNotificationsAlpha, mNotificationsTint);
- if (mScrimForBubble != null) {
- updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
- }
}
}
@@ -1232,14 +1195,6 @@
pw.print(" tint=0x");
pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
- pw.print(" bubbleScrim:");
- pw.print(" viewAlpha=");
- pw.print(mScrimForBubble.getViewAlpha());
- pw.print(" alpha=");
- pw.print(mBubbleAlpha);
- pw.print(" tint=0x");
- pw.println(Integer.toHexString(mScrimForBubble.getTint()));
-
pw.print(" mTracking=");
pw.println(mTracking);
pw.print(" mDefaultScrimAlpha=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0681193..e33c9f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,8 +19,6 @@
import android.graphics.Color;
import android.os.Trace;
-import androidx.annotation.Nullable;
-
import com.android.systemui.dock.DockManager;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -43,11 +41,9 @@
public void prepare(ScrimState previousState) {
mFrontTint = Color.BLACK;
mBehindTint = Color.BLACK;
- mBubbleTint = previousState.mBubbleTint;
mFrontAlpha = 1f;
mBehindAlpha = 1f;
- mBubbleAlpha = previousState.mBubbleAlpha;
mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
}
@@ -81,12 +77,10 @@
mFrontTint = Color.BLACK;
mBehindTint = Color.BLACK;
mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
- mBubbleTint = Color.TRANSPARENT;
mFrontAlpha = 0;
mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
- mBubbleAlpha = 0;
if (mClipQsScrim) {
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
@@ -118,7 +112,6 @@
mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
- mBubbleAlpha = 0f;
}
},
@@ -129,7 +122,6 @@
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = 0;
- mBubbleAlpha = 0f;
mFrontAlpha = mDefaultScrimAlpha;
}
},
@@ -139,7 +131,6 @@
public void prepare(ScrimState previousState) {
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
mNotifAlpha = 1f;
- mBubbleAlpha = 0f;
mFrontAlpha = 0f;
mBehindTint = Color.BLACK;
@@ -163,7 +154,6 @@
public void prepare(ScrimState previousState) {
mBehindAlpha = 0;
mFrontAlpha = 0;
- mBubbleAlpha = 0;
}
},
@@ -185,9 +175,6 @@
mBehindTint = Color.BLACK;
mBehindAlpha = ScrimController.TRANSPARENT;
- mBubbleTint = Color.TRANSPARENT;
- mBubbleAlpha = ScrimController.TRANSPARENT;
-
mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
// DisplayPowerManager may blank the screen for us, or we might blank it for ourselves
// by animating the screen off via the LightRevelScrim. In either case we just need to
@@ -214,7 +201,6 @@
@Override
public void prepare(ScrimState previousState) {
mFrontAlpha = mAodFrontScrimAlpha;
- mBubbleAlpha = 0f;
mBehindTint = Color.BLACK;
mFrontTint = Color.BLACK;
mBlankScreen = mDisplayRequiresBlanking;
@@ -238,7 +224,6 @@
mBehindAlpha = mClipQsScrim ? 1 : 0;
mNotifAlpha = 0;
mFrontAlpha = 0;
- mBubbleAlpha = 0;
mAnimationDuration = mKeyguardFadingAway
? mKeyguardFadingAwayDuration
@@ -248,21 +233,16 @@
mFrontTint = Color.TRANSPARENT;
mBehindTint = Color.BLACK;
- mBubbleTint = Color.TRANSPARENT;
mBlankScreen = false;
if (previousState == ScrimState.AOD) {
// Set all scrims black, before they fade transparent.
updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
- if (mScrimForBubble != null) {
- updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */);
- }
// Scrims should still be black at the end of the transition.
mFrontTint = Color.BLACK;
mBehindTint = Color.BLACK;
- mBubbleTint = Color.BLACK;
mBlankScreen = true;
}
@@ -270,45 +250,24 @@
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
}
- },
-
- /**
- * Unlocked with a bubble expanded.
- */
- BUBBLE_EXPANDED {
- @Override
- public void prepare(ScrimState previousState) {
- mFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.TRANSPARENT;
- mBubbleTint = Color.BLACK;
-
- mFrontAlpha = 0f;
- mBehindAlpha = mDefaultScrimAlpha;
-
- mAnimationDuration = ScrimController.ANIMATION_DURATION;
- mBlankScreen = false;
- }
};
boolean mBlankScreen = false;
long mAnimationDuration = ScrimController.ANIMATION_DURATION;
int mFrontTint = Color.TRANSPARENT;
int mBehindTint = Color.TRANSPARENT;
- int mBubbleTint = Color.TRANSPARENT;
int mNotifTint = Color.TRANSPARENT;
boolean mAnimateChange = true;
float mAodFrontScrimAlpha;
float mFrontAlpha;
float mBehindAlpha;
- float mBubbleAlpha;
float mNotifAlpha;
float mScrimBehindAlphaKeyguard;
float mDefaultScrimAlpha;
ScrimView mScrimInFront;
ScrimView mScrimBehind;
- @Nullable ScrimView mScrimForBubble;
DozeParameters mDozeParameters;
DockManager mDockManager;
@@ -321,11 +280,10 @@
long mKeyguardFadingAwayDuration;
boolean mClipQsScrim;
- public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
- DozeParameters dozeParameters, DockManager dockManager) {
+ public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
+ DockManager dockManager) {
mScrimInFront = scrimInFront;
mScrimBehind = scrimBehind;
- mScrimForBubble = scrimForBubble;
mDozeParameters = dozeParameters;
mDockManager = dockManager;
@@ -352,10 +310,6 @@
return mNotifAlpha;
}
- public float getBubbleAlpha() {
- return mBubbleAlpha;
- }
-
public int getFrontTint() {
return mFrontTint;
}
@@ -368,10 +322,6 @@
return mNotifTint;
}
- public int getBubbleTint() {
- return mBubbleTint;
- }
-
public long getAnimationDuration() {
return mAnimationDuration;
}
@@ -409,10 +359,6 @@
mDefaultScrimAlpha = defaultScrimAlpha;
}
- public void setBubbleAlpha(float alpha) {
- mBubbleAlpha = alpha;
- }
-
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
}
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..0a5fa1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -17,10 +17,11 @@
package com.android.systemui.statusbar.phone
import android.view.View
-import com.android.systemui.BatteryMeterView
import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
import javax.inject.Inject
@@ -31,9 +32,11 @@
@Named(SPLIT_SHADE_HEADER) private val statusBar: View,
private val statusBarIconController: StatusBarIconController,
qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
- featureFlags: FeatureFlags
+ featureFlags: FeatureFlags,
+ batteryMeterViewController: BatteryMeterViewController
) {
+ // TODO(b/194178072) Handle RSSI hiding when multi carrier
private val iconManager: StatusBarIconController.IconManager
private val qsCarrierGroupController: QSCarrierGroupController
private var visible = false
@@ -55,6 +58,7 @@
// battery settings same as in QS icons
batteryIcon.setIgnoreTunerUpdates(true)
batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
+ batteryMeterViewController.init()
val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
iconManager = StatusBarIconController.IconManager(iconContainer, featureFlags)
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..5218dfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -18,7 +18,6 @@
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -32,16 +31,12 @@
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST;
@@ -71,13 +66,10 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
-import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -89,8 +81,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@@ -105,8 +95,6 @@
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
-import android.view.InsetsState;
-import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
@@ -114,7 +102,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsetsController.Appearance;
-import android.view.WindowInsetsController.Behavior;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -134,7 +121,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
-import com.android.internal.view.AppearanceRegion;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
@@ -147,10 +133,10 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.camera.CameraIntents;
@@ -158,13 +144,11 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.emergency.EmergencyGesture;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -191,7 +175,6 @@
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -211,14 +194,11 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
@@ -241,12 +221,12 @@
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-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.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
@@ -266,10 +246,10 @@
import dagger.Lazy;
-public class StatusBar extends SystemUI implements DemoMode,
- ActivityStarter, KeyguardStateController.Callback,
- OnHeadsUpChangedListener, CommandQueue.Callbacks,
- ColorExtractor.OnColorsChangedListener, ConfigurationListener,
+/** */
+public class StatusBar extends SystemUI implements
+ ActivityStarter,
+ ConfigurationListener,
StatusBarStateController.StateListener,
LifecycleOwner, BatteryController.BatteryStateChangeCallback,
ActivityLaunchAnimator.Callback {
@@ -282,7 +262,6 @@
protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
// Should match the values in PhoneWindowManager
- public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
@@ -314,7 +293,7 @@
// 1020-1040 reserved for BaseStatusBar
// Time after we abort the launch transition.
- private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
+ static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
@@ -323,11 +302,6 @@
*/
private static final int HINT_RESET_DELAY_MS = 1200;
- private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .build();
-
public static final int FADE_KEYGUARD_START_DELAY = 100;
public static final int FADE_KEYGUARD_DURATION = 300;
public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
@@ -353,14 +327,113 @@
try {
IPackageManager packageManager =
IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- onlyCoreApps = packageManager.isOnlyCoreApps();
+ onlyCoreApps = packageManager != null && packageManager.isOnlyCoreApps();
} catch (RemoteException e) {
onlyCoreApps = false;
}
ONLY_CORE_APPS = onlyCoreApps;
}
- private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
+
+ void setWindowState(int state) {
+ mStatusBarWindowState = state;
+ mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
+ }
+
+ void acquireGestureWakeLock(long time) {
+ mGestureWakeLock.acquire(time);
+ }
+
+ boolean setAppearance(int appearance) {
+ if (mAppearance != appearance) {
+ mAppearance = appearance;
+ return updateBarMode(barMode(isTransientShown(), appearance));
+ }
+
+ return false;
+ }
+
+ int getBarMode() {
+ return mStatusBarMode;
+ }
+
+ boolean getWereIconsJustHidden() {
+ return mWereIconsJustHidden;
+ }
+
+ void setWereIconsJustHidden(boolean justHidden) {
+ mWereIconsJustHidden = justHidden;
+ }
+
+ void resetHandlerMsg(int msg) {
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ int getDisabled1() {
+ return mDisabled1;
+ }
+
+ void setDisabled1(int disabled) {
+ mDisabled1 = disabled;
+ }
+
+ int getDisabled2() {
+ return mDisabled2;
+ }
+
+ void setDisabled2(int disabled) {
+ mDisabled2 = disabled;
+ }
+
+ void setLastCameraLaunchSource(int source) {
+ mLastCameraLaunchSource = source;
+ }
+
+ void setLaunchCameraOnFinishedGoingToSleep(boolean launch) {
+ mLaunchCameraOnFinishedGoingToSleep = launch;
+ }
+
+ void setLaunchCameraOnFinishedWaking(boolean launch) {
+ mLaunchCameraWhenFinishedWaking = launch;
+ }
+
+ void setLaunchEmergencyActionOnFinishedGoingToSleep(boolean launch) {
+ mLaunchEmergencyActionOnFinishedGoingToSleep = launch;
+ }
+
+ void setLaunchEmergencyActionOnFinishedWaking(boolean launch) {
+ mLaunchEmergencyActionWhenFinishedWaking = launch;
+ }
+
+ void setTopHidesStatusBar(boolean hides) {
+ mTopHidesStatusBar = hides;
+ }
+
+ QSPanelController getQSPanelController() {
+ return mQSPanelController;
+ }
+
+ /** */
+ public void animateExpandNotificationsPanel() {
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
+ }
+
+ /** */
+ public void animateExpandSettingsPanel(@Nullable String subpanel) {
+ mCommandQueueCallbacks.animateExpandSettingsPanel(subpanel);
+ }
+
+ /** */
+ public void animateCollapsePanels(int flags, boolean force) {
+ mCommandQueueCallbacks.animateCollapsePanels(flags, force);
+ }
public interface ExpansionChangedListener {
void onExpansionChanged(float expansion, boolean expanded);
@@ -372,8 +445,7 @@
protected int mState; // TODO: remove this. Just use StatusBarStateController
protected boolean mBouncerShowing;
- private PhoneStatusBarPolicy mIconPolicy;
- private StatusBarSignalPolicy mSignalPolicy;
+ private final PhoneStatusBarPolicy mIconPolicy;
private final VolumeComponent mVolumeComponent;
private BrightnessMirrorController mBrightnessMirrorController;
@@ -384,8 +456,6 @@
@Nullable
protected LockscreenWallpaper mLockscreenWallpaper;
private final AutoHideController mAutoHideController;
- @Nullable
- private final KeyguardLiftController mKeyguardLiftController;
private final Point mCurrentDisplaySize = new Point();
@@ -402,7 +472,6 @@
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private LightRevealScrim mLightRevealScrim;
- private WiredChargingRippleController mChargingRippleAnimationController;
private PowerButtonReveal mPowerButtonReveal;
private final Object mQueueLock = new Object();
@@ -436,12 +505,12 @@
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ExtensionController mExtensionController;
private final UserInfoControllerImpl mUserInfoControllerImpl;
- private final DismissCallbackRegistry mDismissCallbackRegistry;
private final DemoModeController mDemoModeController;
- private NotificationsController mNotificationsController;
+ private final NotificationsController mNotificationsController;
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
@@ -452,8 +521,6 @@
KeyguardIndicationController mKeyguardIndicationController;
- private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
-
private View mReportRejectedTouch;
private boolean mExpandedVisible;
@@ -467,16 +534,20 @@
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 WallpaperManager mWallpaperManager;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
- // for disabling the status bar
+ // Flags for disabling the status bar
+ // Two variables becaseu the first one evidently ran out of room for new flags.
private int mDisabled1 = 0;
private int mDisabled2 = 0;
- /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
+ /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
private boolean mTransientShown;
@@ -562,7 +633,7 @@
private int mInteractingWindows;
private @TransitionMode int mStatusBarMode;
- private ViewMediatorCallback mKeyguardViewMediatorCallback;
+ private final ViewMediatorCallback mKeyguardViewMediatorCallback;
private final ScrimController mScrimController;
protected DozeScrimController mDozeScrimController;
private final Executor mUiBgExecutor;
@@ -582,8 +653,7 @@
Log.wtf(TAG, "WallpaperManager not supported");
return;
}
- WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
- WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
+ WallpaperInfo info = mWallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
// If WallpaperInfo is null, it must be ImageWallpaper.
@@ -598,22 +668,17 @@
BroadcastReceiver mTaskbarChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().onTaskbarChanged(intent.getExtras());
- }
+ mBubblesOptional.ifPresent(bubbles -> bubbles.onTaskbarChanged(intent.getExtras()));
}
};
private Runnable mLaunchTransitionEndRunnable;
- private NotificationEntry mDraggedDownEntry;
private boolean mLaunchCameraWhenFinishedWaking;
private boolean mLaunchCameraOnFinishedGoingToSleep;
private boolean mLaunchEmergencyActionWhenFinishedWaking;
private boolean mLaunchEmergencyActionOnFinishedGoingToSleep;
private int mLastCameraLaunchSource;
protected PowerManager.WakeLock mGestureWakeLock;
- private Vibrator mVibrator;
- private VibrationEffect mCameraLaunchGestureVibrationEffect;
private final int[] mTmpInt2 = new int[2];
@@ -697,20 +762,22 @@
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private boolean mVibrateOnOpening;
- private final VibratorHelper mVibratorHelper;
private ActivityLaunchAnimator mActivityLaunchAnimator;
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
- private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
+ private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
private final Optional<BubblesManager> mBubblesManagerOptional;
private final Optional<Bubbles> mBubblesOptional;
private final Bubbles.BubbleExpandListener mBubbleExpandListener;
private final Optional<StartingSurface> mStartingSurfaceOptional;
- private ActivityIntentHelper mActivityIntentHelper;
+ private final ActivityIntentHelper mActivityIntentHelper;
private NotificationStackScrollLayoutController mStackScrollerController;
+ private BatteryMeterViewController mBatteryMeterViewController;
+
+ private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
+ (extractor, which) -> updateTheme();
/**
* Public constructor for StatusBar.
@@ -725,7 +792,6 @@
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -736,7 +802,6 @@
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
- RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -755,19 +820,16 @@
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
- VibratorHelper vibratorHelper,
Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
- AccessibilityFloatingMenuController accessibilityFloatingMenuController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
DozeParameters dozeParameters,
ScrimController scrimController,
- @Nullable KeyguardLiftController keyguardLiftController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
DozeServiceHost dozeServiceHost,
@@ -794,19 +856,21 @@
UserInfoControllerImpl userInfoControllerImpl,
PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController,
- DismissCallbackRegistry dismissCallbackRegistry,
DemoModeController demoModeController,
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
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,
+ WallpaperManager wallpaperManager,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
Optional<StartingSurface> startingSurfaceOptional) {
super(context);
@@ -814,7 +878,6 @@
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mSignalPolicy = signalPolicy;
mPulseExpansionHandler = pulseExpansionHandler;
mWakeUpCoordinator = notificationWakeUpCoordinator;
mKeyguardBypassController = keyguardBypassController;
@@ -827,7 +890,6 @@
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
- mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -846,7 +908,6 @@
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
- mVibratorHelper = vibratorHelper;
mBubblesManagerOptional = bubblesManagerOptional;
mBubblesOptional = bubblesOptional;
mVisualStabilityManager = visualStabilityManager;
@@ -859,7 +920,6 @@
mPowerManager = powerManager;
mDozeParameters = dozeParameters;
mScrimController = scrimController;
- mKeyguardLiftController = keyguardLiftController;
mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
mScreenPinningRequest = screenPinningRequest;
mDozeScrimController = dozeScrimController;
@@ -882,16 +942,18 @@
mExtensionController = extensionController;
mUserInfoControllerImpl = userInfoControllerImpl;
mIconPolicy = phoneStatusBarPolicy;
- mDismissCallbackRegistry = dismissCallbackRegistry;
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
- mChargingRippleAnimationController = chargingRippleAnimationController;
+ mUnfoldTransitionConfig = unfoldTransitionConfig;
+ mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
+ mStatusBarIconController = statusBarIconController;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mWallpaperManager = wallpaperManager;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
@@ -901,12 +963,10 @@
mExpansionChangedListeners = new ArrayList<>();
mBubbleExpandListener =
- (isExpanding, key) -> {
- mContext.getMainExecutor().execute(() -> {
- mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
- updateScrimController();
- });
- };
+ (isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
+ mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
+ updateScrimController();
+ });
mActivityIntentHelper = new ActivityIntentHelper(mContext);
DateTimeView.setReceiverHandler(timeTickHandler);
@@ -926,7 +986,7 @@
mKeyguardIndicationController.init();
- mColorExtractor.addOnColorsChangedListener(this);
+ mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
mStatusBarStateController.addCallback(this,
SysuiStatusBarStateController.RANK_STATUS_BAR);
@@ -934,13 +994,10 @@
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
- mDisplay = mWindowManager.getDefaultDisplay();
+ mDisplay = mContext.getDisplay();
mDisplayId = mDisplay.getDisplayId();
updateDisplaySize();
- mVibrateOnOpening = mContext.getResources().getBoolean(
- R.bool.config_vibrateOnIconAnimation);
-
// start old BaseStatusBar.start().
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
@@ -954,14 +1011,7 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mWallpaperSupported =
- mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
-
- // Connect in to the status bar manager service
- mCommandQueue.addCallback(this);
-
- // Listen for demo mode changes
- mDemoModeController.addCallback(this);
+ mWallpaperSupported = mWallpaperManager.isWallpaperSupported();
RegisterStatusBarResult result = null;
try {
@@ -988,13 +1038,13 @@
if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
showTransientUnchecked();
}
- onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
- result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedState,
- result.mPackageName);
+ mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
+ result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior,
+ result.mRequestedVisibilities, result.mPackageName);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
- result.mImeBackDisposition, result.mShowImeSwitcher);
+ mCommandQueueCallbacks.setImeWindowStatus(mDisplayId, result.mImeToken,
+ result.mImeWindowVis, result.mImeBackDisposition, result.mShowImeSwitcher);
// Set up the initial icon state
int numIcons = result.mIcons.size();
@@ -1033,7 +1083,13 @@
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy.init();
- mKeyguardStateController.addCallback(this);
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onUnlockedChanged() {
+ updateKeyguardState();
+ logStateToEventlog();
+ }
+ });
startKeyguard();
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
@@ -1058,9 +1114,13 @@
mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
+ if (mUnfoldTransitionConfig.isEnabled()) {
+ mUnfoldLightRevealOverlayAnimation.get().init();
+ }
+
mPluginManager.addPluginListener(
new PluginListener<OverlayPlugin>() {
- private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
+ private final ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
@@ -1109,7 +1169,6 @@
// Constructing the view
// ================================================================================
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
- final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
@@ -1148,6 +1207,11 @@
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+ mBatteryMeterViewController = new BatteryMeterViewController(
+ mStatusBarView.findViewById(R.id.battery)
+ );
+ mBatteryMeterViewController.init();
+
// CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
// mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
// PhoneStatusBarView's new instance will set to be gone in
@@ -1193,13 +1257,18 @@
mStatusBarLocationPublisher,
mNotificationIconAreaController,
mFeatureFlags,
- () -> Optional.of(this)),
+ mStatusBarIconController,
+ mKeyguardStateController,
+ mNetworkController,
+ mStatusBarStateController,
+ () -> Optional.of(this),
+ mCommandQueue
+ ),
CollapsedStatusBarFragment.TAG)
.commit();
mHeadsUpManager.setup(mVisualStabilityManager);
mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView);
- mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
mHeadsUpManager.addListener(mVisualStabilityManager);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
@@ -1224,7 +1293,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mRemoteInputManager.getController().isRemoteInputActive();
+ return !mRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -1242,13 +1311,11 @@
ScrimView notificationsScrim = mNotificationShadeWindowView
.findViewById(R.id.scrim_notifications);
ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
- ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
- ? mBubblesManagerOptional.get().getScrimForBubble() : null;
mScrimController.setScrimVisibleListener(scrimsVisible -> {
mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
});
- mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble);
+ mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
mLightRevealScrim.setRevealAmountListener(
@@ -1329,14 +1396,11 @@
});
}
- if (!mPowerManager.isScreenOn()) {
+ if (!mPowerManager.isInteractive()) {
mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
}
mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
- "GestureWakeLock");
- mVibrator = mContext.getSystemService(Vibrator.class);
- mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
- mVibrator, context.getResources());
+ "sysui:GestureWakeLock");
// receive broadcasts
registerBroadcastReceiver();
@@ -1345,7 +1409,7 @@
if (DEBUG_MEDIA_FAKE_ARTWORK) {
demoFilter.addAction(ACTION_FAKE_ARTWORK);
}
- context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
+ mContext.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
android.Manifest.permission.DUMP, null);
// listen for USER_SETUP_COMPLETE setting (per-user)
@@ -1444,7 +1508,7 @@
mNotificationInterruptStateProvider);
mNotificationShelfController.setOnActivatedListener(mPresenter);
- mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
+ mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mNotificationActivityStarter =
mStatusBarNotificationActivityStarterBuilder
@@ -1579,6 +1643,20 @@
mAuthRippleController = statusBarComponent.getAuthRippleController();
mAuthRippleController.init();
+
+ mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+
+ mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+
+ // Listen for demo mode changes
+ mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode());
+
+ if (mCommandQueueCallbacks != null) {
+ mCommandQueue.removeCallback(mCommandQueueCallbacks);
+ }
+ mCommandQueueCallbacks = statusBarComponent.getStatusBarCommandQueueCallbacks();
+ // Connect in to the status bar manager service
+ mCommandQueue.addCallback(mCommandQueueCallbacks);
}
protected void startKeyguard() {
@@ -1619,7 +1697,7 @@
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
- mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
+ mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager);
mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
@@ -1628,7 +1706,7 @@
Trace.endSection();
}
- protected View getStatusBarView() {
+ protected PhoneStatusBarView getStatusBarView() {
return mStatusBarView;
}
@@ -1690,7 +1768,7 @@
* If the user switcher is simple then disable QS during setup because
* the user intends to use the lock screen user switcher, QS in not needed.
*/
- private void updateQsExpansionEnabled() {
+ void updateQsExpansionEnabled() {
final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
|| !mUserSwitcherController.isSimpleUserSwitcher())
@@ -1706,22 +1784,6 @@
return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
}
- public void addQsTile(ComponentName tile) {
- if (mQSPanelController != null && mQSPanelController.getHost() != null) {
- mQSPanelController.getHost().addTile(tile);
- }
- }
-
- public void remQsTile(ComponentName tile) {
- if (mQSPanelController != null && mQSPanelController.getHost() != null) {
- mQSPanelController.getHost().removeTile(tile);
- }
- }
-
- public void clickTile(ComponentName tile) {
- mQSPanelController.clickTile(tile);
- }
-
/**
* Request a notification update
* @param reason why we're requesting a notification update
@@ -1747,94 +1809,6 @@
&& mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
}
- /**
- * State is one or more of the DISABLE constants from StatusBarManager.
- */
- @Override
- public void disable(int displayId, int state1, int state2, boolean animate) {
- if (displayId != mDisplayId) {
- return;
- }
- state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
-
- animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
- final int old1 = mDisabled1;
- final int diff1 = state1 ^ old1;
- mDisabled1 = state1;
-
- final int old2 = mDisabled2;
- final int diff2 = state2 ^ old2;
- mDisabled2 = state2;
-
- if (DEBUG) {
- Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
- old1, state1, diff1));
- Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
- old2, state2, diff2));
- }
-
- StringBuilder flagdbg = new StringBuilder();
- flagdbg.append("disable<");
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
- flagdbg.append("> disable2<");
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
- flagdbg.append('>');
- Log.d(TAG, flagdbg.toString());
-
- if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
- mShadeController.animateCollapsePanels();
- }
- }
-
- if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
- if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
- // close recents if it's visible
- mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
- mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
- }
- }
-
- if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- if (areNotificationAlertsDisabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
- }
-
- if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
- updateQsExpansionEnabled();
- }
-
- if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- updateQsExpansionEnabled();
- if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- mShadeController.animateCollapsePanels();
- }
- }
- }
-
boolean areNotificationAlertsDisabled() {
return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
}
@@ -1899,70 +1873,6 @@
logStateToEventlog();
}
- @Override
- public void onUnlockedChanged() {
- updateKeyguardState();
- logStateToEventlog();
- }
-
- @Override
- public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
- if (inPinnedMode) {
- mNotificationShadeWindowController.setHeadsUpShowing(true);
- mStatusBarWindowController.setForceStatusBarVisible(true);
- if (mNotificationPanelViewController.isFullyCollapsed()) {
- // We need to ensure that the touchable region is updated before the window will be
- // resized, in order to not catch any touches. A layout will ensure that
- // onComputeInternalInsets will be called and after that we can resize the layout. Let's
- // make sure that the window stays small for one frame until the touchableRegion is set.
- mNotificationPanelViewController.getView().requestLayout();
- mNotificationShadeWindowController.setForceWindowCollapsed(true);
- mNotificationPanelViewController.getView().post(() -> {
- mNotificationShadeWindowController.setForceWindowCollapsed(false);
- });
- }
- } else {
- boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
- && mState == StatusBarState.KEYGUARD;
- if (!mNotificationPanelViewController.isFullyCollapsed()
- || mNotificationPanelViewController.isTracking() || bypassKeyguard) {
- // We are currently tracking or is open and the shade doesn't need to be kept
- // open artificially.
- mNotificationShadeWindowController.setHeadsUpShowing(false);
- if (bypassKeyguard) {
- mStatusBarWindowController.setForceStatusBarVisible(false);
- }
- } else {
- // we need to keep the panel open artificially, let's wait until the animation
- // is finished.
- mHeadsUpManager.setHeadsUpGoingAway(true);
- mNotificationPanelViewController.runAfterAnimationFinished(() -> {
- if (!mHeadsUpManager.hasPinnedHeadsUp()) {
- mNotificationShadeWindowController.setHeadsUpShowing(false);
- mHeadsUpManager.setHeadsUpGoingAway(false);
- }
- mRemoteInputManager.onPanelCollapsed();
- });
- }
- }
- }
-
- @Override
- public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
- if (mStatusBarStateController.isDozing() && isHeadsUp) {
- entry.setPulseSuppressed(false);
- mDozeServiceHost.fireNotificationPulse(entry);
- if (mDozeServiceHost.isPulsing()) {
- mDozeScrimController.cancelPendingPulseTimeout();
- }
- }
- if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
- // There are no longer any notifications to show. We should end the pulse now.
- mDozeScrimController.pulseOutNow();
- }
- }
-
public void setPanelExpanded(boolean isExpanded) {
if (mPanelExpanded != isExpanded) {
mNotificationLogger.onPanelExpandedChanged(isExpanded);
@@ -1995,11 +1905,6 @@
return mNotificationPanelViewController.hideStatusBarIconsWhenExpanded();
}
- @Override
- public void onColorsChanged(ColorExtractor extractor, int which) {
- updateTheme();
- }
-
@Nullable
public View getAmbientIndicationContainer() {
return mAmbientIndicationContainer;
@@ -2035,7 +1940,7 @@
*
* @param animate should the change of the icons be animated.
*/
- private void updateHideIconsForBouncer(boolean animate) {
+ void updateHideIconsForBouncer(boolean animate) {
boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
&& (mStatusBarWindowHidden || mBouncerShowing);
boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
@@ -2149,15 +2054,14 @@
mState = state;
}
- @VisibleForTesting
- void setUserSetupForTest(boolean userSetup) {
- mUserSetup = userSetup;
- }
-
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
protected class H extends Handler {
+ H() {
+ super(Looper.myLooper());
+ }
+
@Override
public void handleMessage(Message m) {
switch (m.what) {
@@ -2169,10 +2073,10 @@
break;
// End old BaseStatusBar.H handling.
case MSG_OPEN_NOTIFICATION_PANEL:
- animateExpandNotificationsPanel();
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
break;
case MSG_OPEN_SETTINGS_PANEL:
- animateExpandSettingsPanel((String) m.obj);
+ mCommandQueueCallbacks.animateExpandSettingsPanel((String) m.obj);
break;
case MSG_CLOSE_PANELS:
mShadeController.animateCollapsePanels();
@@ -2204,59 +2108,6 @@
mHeadsUpManager.releaseAllImmediately();
}
- /**
- * Called for system navigation gestures. First action opens the panel, second opens
- * settings. Down action closes the entire panel.
- */
- @Override
- public void handleSystemKey(int key) {
- if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
- if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
- || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
- return;
- }
-
- // Panels are not available in setup
- if (!mUserSetup) return;
-
- if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
- mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
- mNotificationPanelViewController.collapse(
- false /* delayed */, 1.0f /* speedUpFactor */);
- } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
- mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
- if (mNotificationPanelViewController.isFullyCollapsed()) {
- if (mVibrateOnOpening) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
- }
- mNotificationPanelViewController.expand(true /* animate */);
- mStackScroller.setWillExpand(true);
- mHeadsUpManager.unpinAll(true /* userUnpinned */);
- mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
- } else if (!mNotificationPanelViewController.isInSettings()
- && !mNotificationPanelViewController.isExpanding()) {
- mNotificationPanelViewController.flingSettings(0 /* velocity */,
- NotificationPanelView.FLING_EXPAND);
- mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
- }
- }
-
- }
-
- @Override
- public void showPinningEnterExitToast(boolean entering) {
- if (getNavigationBarView() != null) {
- getNavigationBarView().showPinningEnterExitToast(entering);
- }
- }
-
- @Override
- public void showPinningEscapeToast() {
- if (getNavigationBarView() != null) {
- getNavigationBarView().showPinningEscapeToast();
- }
- }
-
void makeExpandedVisible(boolean force) {
if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
@@ -2287,21 +2138,6 @@
mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
}
- @Override
- public void togglePanel() {
- if (mPanelExpanded) {
- mShadeController.animateCollapsePanels();
- } else {
- animateExpandNotificationsPanel();
- }
- }
-
- @Override
- public void animateCollapsePanels(int flags, boolean force) {
- mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
-
/**
* Called by {@link ShadeController} when it calls
* {@link ShadeController#animateCollapsePanels(int, boolean, boolean, float)}.
@@ -2336,36 +2172,6 @@
}
}
- @Override
- public void animateExpandNotificationsPanel() {
- if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!mCommandQueue.panelsEnabled()) {
- return ;
- }
-
- mNotificationPanelViewController.expandWithoutQs();
-
- if (false) postStartTracing();
- }
-
- @Override
- public void animateExpandSettingsPanel(@Nullable String subPanel) {
- if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!mCommandQueue.panelsEnabled()) {
- return;
- }
-
- // Settings are not available in setup
- if (!mUserSetup) return;
-
- if (subPanel != null) {
- mQSPanelController.openDetails(subPanel);
- }
- mNotificationPanelViewController.expandWithQs();
-
- if (false) postStartTracing();
- }
-
public void animateCollapseQuickSettings() {
if (mState == StatusBarState.SHADE) {
mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
@@ -2445,11 +2251,7 @@
final boolean upOrCancel =
event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL;
- if (upOrCancel && !mExpandedVisible) {
- setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
- } else {
- setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
- }
+ setInteracting(StatusBarManager.WINDOW_STATUS_BAR, !upOrCancel || mExpandedVisible);
}
return false;
}
@@ -2466,63 +2268,7 @@
return mBiometricUnlockController;
}
- @Override // CommandQueue
- public void setWindowState(
- int displayId, @WindowType int window, @WindowVisibleState int state) {
- if (displayId != mDisplayId) {
- return;
- }
- boolean showing = state == WINDOW_STATE_SHOWING;
- if (mNotificationShadeWindowView != null
- && window == StatusBarManager.WINDOW_STATUS_BAR
- && mStatusBarWindowState != state) {
- mStatusBarWindowState = state;
- if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
- if (mStatusBarView != null) {
- if (!showing && mState == StatusBarState.SHADE) {
- mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
- mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
- updateHideIconsForBouncer(false /* animate */);
- }
- }
-
- updateBubblesVisibility();
- }
-
- @Override
- public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
- AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
- if (displayId != mDisplayId) {
- return;
- }
- boolean barModeChanged = false;
- if (mAppearance != appearance) {
- mAppearance = appearance;
- barModeChanged = updateBarMode(barMode(mTransientShown, appearance));
- }
- mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
- mStatusBarMode, navbarColorManagedByIme);
-
- updateBubblesVisibility();
- mStatusBarStateController.setSystemBarAttributes(
- appearance, behavior, requestedState, packageName);
- }
-
- @Override
- public void showTransient(int displayId, @InternalInsetsType int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (!containsType(types, ITYPE_STATUS_BAR)) {
- return;
- }
- showTransientUnchecked();
- }
-
- private void showTransientUnchecked() {
+ void showTransientUnchecked() {
if (!mTransientShown) {
mTransientShown = true;
mNoAnimationOnNextBarModeChange = true;
@@ -2530,18 +2276,8 @@
}
}
- @Override
- public void abortTransient(int displayId, @InternalInsetsType int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (!containsType(types, ITYPE_STATUS_BAR)) {
- return;
- }
- clearTransient();
- }
- private void clearTransient() {
+ void clearTransient() {
if (mTransientShown) {
mTransientShown = false;
handleTransientChanged();
@@ -2583,8 +2319,7 @@
}
}
- @Override
- public void showWirelessChargingAnimation(int batteryLevel) {
+ protected void showWirelessChargingAnimation(int batteryLevel) {
showChargingAnimation(batteryLevel, UNKNOWN_BATTERY_LEVEL, 0);
}
@@ -2605,11 +2340,6 @@
}, false, sUiEventLogger).show(animationDelay);
}
- @Override
- public void onRecentsAnimationStateChanged(boolean running) {
- setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
- }
-
protected BarTransitions getStatusBarTransitions() {
return mNotificationShadeWindowViewController.getBarTransitions();
}
@@ -2629,13 +2359,11 @@
}
/** Temporarily hides Bubbles if the status bar is hidden. */
- private void updateBubblesVisibility() {
- if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().onStatusBarVisibilityChanged(
- mStatusBarMode != MODE_LIGHTS_OUT
- && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
- && !mStatusBarWindowHidden);
- }
+ void updateBubblesVisibility() {
+ mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
+ mStatusBarMode != MODE_LIGHTS_OUT
+ && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
+ && !mStatusBarWindowHidden));
}
void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
@@ -2719,7 +2447,7 @@
mNotificationPanelViewController.dump(fd, pw, args);
}
pw.println(" mStackScroller: ");
- if (mStackScroller instanceof Dumpable) {
+ if (mStackScroller != null) {
pw.print (" ");
((Dumpable) mStackScroller).dump(fd, pw, args);
}
@@ -2741,25 +2469,17 @@
mScrimController.dump(fd, pw, args);
}
+ if (mLightRevealScrim != null) {
+ pw.println(
+ "mLightRevealScrim.getRevealAmount(): " + mLightRevealScrim.getRevealAmount());
+ }
+
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.dump(pw);
}
mNotificationsController.dump(fd, pw, args, DUMPTRUCK);
- if (DUMPTRUCK) {
- if (false) {
- pw.println("see the logcat for a dump of the views we have created.");
- // must happen on ui thread
- mHandler.post(() -> {
- mStatusBarView.getLocationOnScreen(mAbsPos);
- Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
- ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
- mStatusBarView.debug();
- });
- }
- }
-
if (DEBUG_GESTURES) {
pw.print(" status bar gestures: ");
mGestureRec.dump(fd, pw, args);
@@ -2790,7 +2510,7 @@
pw.println(" Insecure camera: " + CameraIntents.getInsecureCameraIntent(mContext));
pw.println(" Secure camera: " + CameraIntents.getSecureCameraIntent(mContext));
pw.println(" Override package: "
- + String.valueOf(CameraIntents.getOverrideCameraPackage(mContext)));
+ + CameraIntents.getOverrideCameraPackage(mContext));
}
public static void dumpBarTransitions(
@@ -2851,7 +2571,7 @@
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
}
- private void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
+ void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
final Callback callback, int flags,
@Nullable ActivityLaunchAnimator.Controller animationController) {
@@ -2896,7 +2616,7 @@
options.setRotationAnimationHint(
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
}
- if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
+ if (intent.getAction().equals(Settings.Panel.ACTION_VOLUME)) {
// Settings Panel is implemented as activity(not a dialog), so
// underlying app is paused and may enter picture-in-picture mode
// as a result.
@@ -2995,7 +2715,7 @@
&& mStatusBarKeyguardViewManager.isOccluded()) {
mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
} else {
- AsyncTask.execute(runnable);
+ mHandler.post(runnable);
}
}
if (dismissShade) {
@@ -3037,9 +2757,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();
}
@@ -3280,37 +2998,6 @@
| ((currentlyInsecure ? 1 : 0) << 12);
}
- //
- // tracing
- //
-
- void postStartTracing() {
- mHandler.postDelayed(mStartTracing, 3000);
- }
-
- void vibrate() {
- android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
- Context.VIBRATOR_SERVICE);
- vib.vibrate(250, VIBRATION_ATTRIBUTES);
- }
-
- final Runnable mStartTracing = new Runnable() {
- @Override
- public void run() {
- vibrate();
- SystemClock.sleep(250);
- Log.d(TAG, "startTracing");
- android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
- mHandler.postDelayed(mStopTracing, 10000);
- }
- };
-
- final Runnable mStopTracing = () -> {
- android.os.Debug.stopMethodTracing();
- Log.d(TAG, "stopTracing");
- vibrate();
- };
-
@Override
public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
mHandler.post(() -> {
@@ -3351,82 +3038,6 @@
delay);
}
- @Override
- public List<String> demoCommands() {
- List<String> s = new ArrayList<>();
- s.add(DemoMode.COMMAND_BARS);
- s.add(DemoMode.COMMAND_CLOCK);
- s.add(DemoMode.COMMAND_OPERATOR);
- return s;
- }
-
- @Override
- public void onDemoModeStarted() {
- // Must send this message to any view that we delegate to via dispatchDemoCommandToView
- dispatchDemoModeStartedToView(R.id.clock);
- dispatchDemoModeStartedToView(R.id.operator_name);
- }
-
- @Override
- public void onDemoModeFinished() {
- dispatchDemoModeFinishedToView(R.id.clock);
- dispatchDemoModeFinishedToView(R.id.operator_name);
- checkBarModes();
- }
-
- @Override
- public void dispatchDemoCommand(String command, @NonNull Bundle args) {
- if (command.equals(COMMAND_CLOCK)) {
- dispatchDemoCommandToView(command, args, R.id.clock);
- }
- if (command.equals(COMMAND_BARS)) {
- String mode = args.getString("mode");
- int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
- "translucent".equals(mode) ? MODE_TRANSLUCENT :
- "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
- "transparent".equals(mode) ? MODE_TRANSPARENT :
- "warning".equals(mode) ? MODE_WARNING :
- -1;
- if (barMode != -1) {
- boolean animate = true;
- if (mNotificationShadeWindowController != null
- && mNotificationShadeWindowViewController.getBarTransitions() != null) {
- mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
- barMode, animate);
- }
- mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
- }
- }
- if (command.equals(COMMAND_OPERATOR)) {
- dispatchDemoCommandToView(command, args, R.id.operator_name);
- }
- }
-
- //TODO: these should have controllers, and this method should be removed
- private void dispatchDemoCommandToView(String command, Bundle args, int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
- }
- }
-
- private void dispatchDemoModeStartedToView(int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).onDemoModeStarted();
- }
- }
-
- private void dispatchDemoModeFinishedToView(int id) {
- if (mStatusBarView == null) return;
- View v = mStatusBarView.findViewById(id);
- if (v instanceof DemoModeCommandReceiver) {
- ((DemoModeCommandReceiver) v).onDemoModeFinished();
- }
- }
-
public void showKeyguard() {
mStatusBarStateController.setKeyguardRequested(true);
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
@@ -3567,7 +3178,7 @@
*/
public void animateKeyguardUnoccluding() {
mNotificationPanelViewController.setExpandedFraction(0f);
- animateExpandNotificationsPanel();
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
}
/**
@@ -3605,6 +3216,7 @@
mIsKeyguard = false;
Trace.beginSection("StatusBar#hideKeyguard");
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
+ int previousState = mStatusBarStateController.getState();
if (!(mStatusBarStateController.setState(StatusBarState.SHADE, force))) {
//TODO: StatusBarStateController should probably know about hiding the keyguard and
// notify listeners.
@@ -3617,7 +3229,7 @@
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
}
long delay = mKeyguardStateController.calculateGoingToFullShadeDelay();
- mLockscreenShadeTransitionController.onHideKeyguard(delay);
+ mLockscreenShadeTransitionController.onHideKeyguard(delay, previousState);
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3737,7 +3349,7 @@
/**
* While IME is active and a BACK event is detected, check with
- * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme(KeyEvent)} to see if the event
+ * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
* should be handled before routing to IME, in order to prevent the user having to hit back
* twice to exit bouncer.
*/
@@ -3939,7 +3551,11 @@
|| !wakingUp && mWakefulnessLifecycle.getLastSleepReason()
== PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
mLightRevealScrim.setRevealEffect(mPowerButtonReveal);
- } else if (!(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ } else if (!wakingUp || !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ // If we're going to sleep, but it's not from the power button, use the default reveal.
+ // If we're waking up, only use the default reveal if the biometric controller didn't
+ // already set it to the circular reveal because we're waking up from a fingerprint/face
+ // auth.
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
}
}
@@ -3968,7 +3584,7 @@
public void onUnlockHintStarted() {
mFalsingCollector.onUnlockHintStarted();
- mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
+ mKeyguardIndicationController.showActionToUnlock();
}
public void onHintFinished() {
@@ -4059,7 +3675,8 @@
// This gets executed before we will show Keyguard, so post it in order that the state
// is correct.
- mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
+ mHandler.post(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
+ mLastCameraLaunchSource));
}
if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
@@ -4067,7 +3684,8 @@
// This gets executed before we will show Keyguard, so post it in order that the
// state is correct.
- mHandler.post(() -> onEmergencyActionLaunchGestureDetected());
+ mHandler.post(
+ () -> mCommandQueueCallbacks.onEmergencyActionLaunchGestureDetected());
}
updateIsKeyguard();
}
@@ -4180,36 +3798,6 @@
return mWakefulnessLifecycle.getWakefulness();
}
- private void vibrateForCameraGesture() {
- // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
- mVibrator.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES);
- }
-
- private static VibrationEffect getCameraGestureVibrationEffect(Vibrator vibrator,
- Resources resources) {
- if (vibrator.areAllPrimitivesSupported(
- VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
- VibrationEffect.Composition.PRIMITIVE_CLICK)) {
- return VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
- .compose();
- }
- if (vibrator.hasAmplitudeControl()) {
- return VibrationEffect.createWaveform(
- CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
- CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
- /* repeat= */ -1);
- }
-
- int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
- long[] timings = new long[pattern.length];
- for (int i = 0; i < pattern.length; i++) {
- timings[i] = pattern[i];
- }
- return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
- }
-
/**
* @return true if the screen is currently fully off, i.e. has finished turning off and has
* since not started turning on.
@@ -4218,139 +3806,11 @@
return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
}
- @Override
- public void showScreenPinningRequest(int taskId) {
- if (mKeyguardStateController.isShowing()) {
- // Don't allow apps to trigger this from keyguard.
- return;
- }
- // Show screen pinning request, since this comes from an app, show 'no thanks', button.
- showScreenPinningRequest(taskId, true);
- }
-
public void showScreenPinningRequest(int taskId, boolean allowCancel) {
mScreenPinningRequest.showPrompt(taskId, allowCancel);
}
- @Override
- public void appTransitionCancelled(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
- }
- }
-
- @Override
- public void appTransitionFinished(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
- }
- }
-
- @Override
- public void onCameraLaunchGestureDetected(int source) {
- mLastCameraLaunchSource = source;
- if (isGoingToSleep()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
- mLaunchCameraOnFinishedGoingToSleep = true;
- return;
- }
- if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now");
- return;
- }
- if (!mDeviceInteractive) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
- "com.android.systemui:CAMERA_GESTURE");
- }
- vibrateForCameraGesture();
-
- if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
- Log.v(TAG, "Camera launch");
- mKeyguardUpdateMonitor.onCameraLaunched();
- }
-
- if (!mStatusBarKeyguardViewManager.isShowing()) {
- final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
- startActivityDismissingKeyguard(cameraIntent,
- false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
- } else {
- if (!mDeviceInteractive) {
- // Avoid flickering of the scrim when we instant launch the camera and the bouncer
- // comes on.
- mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
- }
- if (isWakingUpOrAwake()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.reset(true /* hide */);
- }
- mNotificationPanelViewController.launchCamera(
- mDeviceInteractive /* animate */, source);
- updateScrimController();
- } else {
- // We need to defer the camera launch until the screen comes on, since otherwise
- // we will dismiss us too early since we are waiting on an activity to be drawn and
- // incorrectly get notified because of the screen on event (which resumes and pauses
- // some activities)
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
- mLaunchCameraWhenFinishedWaking = true;
- }
- }
- }
-
- @Override
- public void onEmergencyActionLaunchGestureDetected() {
- Intent emergencyIntent = getEmergencyActionIntent();
-
- if (emergencyIntent == null) {
- Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
- return;
- }
-
- if (isGoingToSleep()) {
- mLaunchEmergencyActionOnFinishedGoingToSleep = true;
- return;
- }
-
- if (!mDeviceInteractive) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis(),
- PowerManager.WAKE_REASON_GESTURE,
- "com.android.systemui:EMERGENCY_GESTURE");
- }
- // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
- // app-side haptic experimentation.
-
- if (!mStatusBarKeyguardViewManager.isShowing()) {
- startActivityDismissingKeyguard(emergencyIntent,
- false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
- return;
- }
-
- if (!mDeviceInteractive) {
- // Avoid flickering of the scrim when we instant launch the camera and the bouncer
- // comes on.
- mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
- }
-
- if (isWakingUpOrAwake()) {
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.reset(true /* hide */);
- }
- mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
- return;
- }
- // We need to defer the emergency action launch until the screen comes on, since otherwise
- // we will dismiss us too early since we are waiting on an activity to be drawn and
- // incorrectly get notified because of the screen on event (which resumes and pauses
- // some activities)
- mLaunchEmergencyActionWhenFinishedWaking = true;
- }
-
- private @Nullable Intent getEmergencyActionIntent() {
+ @Nullable Intent getEmergencyActionIntent() {
Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> emergencyActivities = pm.queryIntentActivities(emergencyIntent,
@@ -4408,16 +3868,11 @@
return true;
}
- private boolean isGoingToSleep() {
+ boolean isGoingToSleep() {
return mWakefulnessLifecycle.getWakefulness()
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
}
- private boolean isWakingUpOrAwake() {
- return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
- || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
- }
-
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
updateScrimController();
@@ -4472,8 +3927,6 @@
mScrimController.transitionTo(ScrimState.AOD);
} else if (mIsKeyguard && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- } else if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
- mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
@@ -4570,10 +4023,6 @@
mNotificationsController.setNotificationSnoozed(sbn, snoozeOption);
}
- @Override
- public void toggleSplitScreen() {
- toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
- }
public void awakenDreams() {
mUiBgExecutor.execute(() -> {
@@ -4585,46 +4034,6 @@
});
}
- @Override
- public void preloadRecentApps() {
- int msg = MSG_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void cancelPreloadRecentApps() {
- int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void dismissKeyboardShortcutsMenu() {
- int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void toggleKeyboardShortcutsMenu(int deviceId) {
- int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
- }
-
- @Override
- public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
- mTopHidesStatusBar = topAppHidesStatusBar;
- if (!topAppHidesStatusBar && mWereIconsJustHidden) {
- // Immediately update the icon hidden state, since that should only apply if we're
- // staying fullscreen.
- mWereIconsJustHidden = false;
- mCommandQueue.recomputeDisableFlags(mDisplayId, true);
- }
- updateHideIconsForBouncer(true /* animate */);
- }
-
protected void toggleKeyboardShortcuts(int deviceId) {
KeyboardShortcuts.toggle(mContext, deviceId);
}
@@ -4886,34 +4295,19 @@
}
return mStatusBarKeyguardViewManager.isSecure();
}
-
- @Override
- public void showAssistDisclosure() {
- mAssistManagerLazy.get().showDisclosure();
- }
-
public NotificationPanelViewController getPanelController() {
return mNotificationPanelViewController;
}
-
- @Override
- public void startAssist(Bundle args) {
- mAssistManagerLazy.get().startAssist(args);
- }
// End Extra BaseStatusBarMethods.
public NotificationGutsManager getGutsManager() {
return mGutsManager;
}
- private boolean isTransientShown() {
+ boolean isTransientShown() {
return mTransientShown;
}
- @Override
- public void suppressAmbientDisplay(boolean suppressed) {
- mDozeServiceHost.setDozeSuppressed(suppressed);
- }
public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
mExpansionChangedListeners.add(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
new file mode 100644
index 0000000..95f2d0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.windowStateToString;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.containsType;
+
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+
+import android.annotation.Nullable;
+import android.app.StatusBarManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.AudioAttributes;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.Log;
+import android.util.Slog;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
+import android.view.KeyEvent;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.AppearanceRegion;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.qs.QSPanelController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
+ private final StatusBar mStatusBar;
+ private final Context mContext;
+ private final ShadeController mShadeController;
+ private final CommandQueue mCommandQueue;
+ private final NotificationPanelViewController mNotificationPanelViewController;
+ private final Optional<LegacySplitScreen> mSplitScreenOptional;
+ private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final MetricsLogger mMetricsLogger;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final KeyguardStateController mKeyguardStateController;
+ private final HeadsUpManager mHeadsUpManager;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final AssistManager mAssistManager;
+ private final DozeServiceHost mDozeServiceHost;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+ private final NotificationShadeWindowView mNotificationShadeWindowView;
+ private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ private final PowerManager mPowerManager;
+ private final VibratorHelper mVibratorHelper;
+ private final Optional<Vibrator> mVibratorOptional;
+ private final LightBarController mLightBarController;
+ private final int mDisplayId;
+ private final boolean mVibrateOnOpening;
+ private final VibrationEffect mCameraLaunchGestureVibrationEffect;
+
+
+ private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
+ @Inject
+ StatusBarCommandQueueCallbacks(
+ StatusBar statusBar,
+ Context context,
+ @Main Resources resources,
+ ShadeController shadeController,
+ CommandQueue commandQueue,
+ NotificationPanelViewController notificationPanelViewController,
+ Optional<LegacySplitScreen> splitScreenOptional,
+ RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+ MetricsLogger metricsLogger,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ KeyguardStateController keyguardStateController,
+ HeadsUpManager headsUpManager,
+ WakefulnessLifecycle wakefulnessLifecycle,
+ DeviceProvisionedController deviceProvisionedController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ AssistManager assistManager,
+ DozeServiceHost dozeServiceHost,
+ SysuiStatusBarStateController statusBarStateController,
+ NotificationShadeWindowView notificationShadeWindowView,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController,
+ PowerManager powerManager,
+ VibratorHelper vibratorHelper,
+ Optional<Vibrator> vibratorOptional,
+ LightBarController lightBarController,
+ @DisplayId int displayId) {
+
+ mStatusBar = statusBar;
+ mContext = context;
+ mShadeController = shadeController;
+ mCommandQueue = commandQueue;
+ mNotificationPanelViewController = notificationPanelViewController;
+ mSplitScreenOptional = splitScreenOptional;
+ mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
+ mMetricsLogger = metricsLogger;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardStateController = keyguardStateController;
+ mHeadsUpManager = headsUpManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mAssistManager = assistManager;
+ mDozeServiceHost = dozeServiceHost;
+ mStatusBarStateController = statusBarStateController;
+ mNotificationShadeWindowView = notificationShadeWindowView;
+ mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
+ mPowerManager = powerManager;
+ mVibratorHelper = vibratorHelper;
+ mVibratorOptional = vibratorOptional;
+ mLightBarController = lightBarController;
+ mDisplayId = displayId;
+
+ mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
+ mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
+ mVibratorOptional, resources);
+ }
+
+ @Override
+ public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ if (!containsType(types, ITYPE_STATUS_BAR)) {
+ return;
+ }
+ mStatusBar.clearTransient();
+ }
+
+ @Override
+ public void addQsTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null && qsPanelController.getHost() != null) {
+ qsPanelController.getHost().addTile(tile);
+ }
+ }
+
+ @Override
+ public void remQsTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null && qsPanelController.getHost() != null) {
+ qsPanelController.getHost().removeTile(tile);
+ }
+ }
+
+ @Override
+ public void clickTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null) {
+ qsPanelController.clickTile(tile);
+ }
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force) {
+ mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
+ 1.0f /* speedUpFactor */);
+ }
+
+ @Override
+ public void animateExpandNotificationsPanel() {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG,
+ "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+ }
+ if (!mCommandQueue.panelsEnabled()) {
+ return;
+ }
+
+ mNotificationPanelViewController.expandWithoutQs();
+ }
+
+ @Override
+ public void animateExpandSettingsPanel(@Nullable String subPanel) {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG,
+ "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+ }
+ if (!mCommandQueue.panelsEnabled()) {
+ return;
+ }
+
+ // Settings are not available in setup
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (subPanel != null && qsPanelController != null) {
+ qsPanelController.openDetails(subPanel);
+ }
+ mNotificationPanelViewController.expandWithQs();
+ }
+
+ @Override
+ public void appTransitionCancelled(int displayId) {
+ if (displayId == mDisplayId) {
+ mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+ }
+ }
+
+ @Override
+ public void appTransitionFinished(int displayId) {
+ if (displayId == mDisplayId) {
+ mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+ }
+ }
+
+ @Override
+ public void preloadRecentApps() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_PRELOAD_RECENT_APPS);
+ }
+
+ @Override
+ public void cancelPreloadRecentApps() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_CANCEL_PRELOAD_RECENT_APPS);
+ }
+
+ @Override
+ public void dismissKeyboardShortcutsMenu() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU);
+ }
+ /**
+ * State is one or more of the DISABLE constants from StatusBarManager.
+ */
+ @Override
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
+ final int old1 = mStatusBar.getDisabled1();
+ final int diff1 = state1 ^ old1;
+ mStatusBar.setDisabled1(state1);
+
+ final int old2 = mStatusBar.getDisabled2();
+ final int diff2 = state2 ^ old2;
+ mStatusBar.setDisabled2(state2);
+
+ if (StatusBar.DEBUG) {
+ Log.d(StatusBar.TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
+ old1, state1, diff1));
+ Log.d(StatusBar.TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
+ old2, state2, diff2));
+ }
+
+ StringBuilder flagdbg = new StringBuilder();
+ flagdbg.append("disable<");
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
+ flagdbg.append("> disable2<");
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
+ flagdbg.append('>');
+ Log.d(StatusBar.TAG, flagdbg.toString());
+
+ if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+ mShadeController.animateCollapsePanels();
+ }
+ }
+
+ if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
+ // close recents if it's visible
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_HIDE_RECENT_APPS);
+ }
+ }
+
+ if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
+ if (mStatusBar.areNotificationAlertsDisabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
+
+ if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
+ mStatusBar.updateQsExpansionEnabled();
+ }
+
+ if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ mStatusBar.updateQsExpansionEnabled();
+ if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ mShadeController.animateCollapsePanels();
+ }
+ }
+ }
+
+ /**
+ * Called for system navigation gestures. First action opens the panel, second opens
+ * settings. Down action closes the entire panel.
+ */
+ @Override
+ public void handleSystemKey(int key) {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG, "handleNavigationKey: " + key);
+ }
+ if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
+ || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
+ return;
+ }
+
+ // Panels are not available in setup
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+ if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
+ mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
+ mNotificationPanelViewController.collapse(
+ false /* delayed */, 1.0f /* speedUpFactor */);
+ } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
+ mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
+ if (mNotificationPanelViewController.isFullyCollapsed()) {
+ if (mVibrateOnOpening) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ }
+ mNotificationPanelViewController.expand(true /* animate */);
+ mNotificationStackScrollLayoutController.setWillExpand(true);
+ mHeadsUpManager.unpinAll(true /* userUnpinned */);
+ mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
+ } else if (!mNotificationPanelViewController.isInSettings()
+ && !mNotificationPanelViewController.isExpanding()) {
+ mNotificationPanelViewController.flingSettings(0 /* velocity */,
+ NotificationPanelView.FLING_EXPAND);
+ mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
+ }
+ }
+
+ }
+
+ @Override
+ public void onCameraLaunchGestureDetected(int source) {
+ mStatusBar.setLastCameraLaunchSource(source);
+ if (mStatusBar.isGoingToSleep()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Finish going to sleep before launching camera");
+ }
+ mStatusBar.setLaunchCameraOnFinishedGoingToSleep(true);
+ return;
+ }
+ if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Can't launch camera right now");
+ }
+ return;
+ }
+ if (!mStatusBar.isDeviceInteractive()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+ "com.android.systemui:CAMERA_GESTURE");
+ }
+ vibrateForCameraGesture();
+
+ if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+ Log.v(StatusBar.TAG, "Camera launch");
+ mKeyguardUpdateMonitor.onCameraLaunched();
+ }
+
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
+ mStatusBar.startActivityDismissingKeyguard(cameraIntent,
+ false /* onlyProvisioned */, true /* dismissShade */,
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
+ } else {
+ if (!mStatusBar.isDeviceInteractive()) {
+ // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+ // comes on.
+ mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+ }
+ if (isWakingUpOrAwake()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Launching camera");
+ }
+ if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ mStatusBarKeyguardViewManager.reset(true /* hide */);
+ }
+ mNotificationPanelViewController.launchCamera(
+ mStatusBar.isDeviceInteractive() /* animate */, source);
+ mStatusBar.updateScrimController();
+ } else {
+ // We need to defer the camera launch until the screen comes on, since otherwise
+ // we will dismiss us too early since we are waiting on an activity to be drawn and
+ // incorrectly get notified because of the screen on event (which resumes and pauses
+ // some activities)
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Deferring until screen turns on");
+ }
+ mStatusBar.setLaunchCameraOnFinishedWaking(true);
+ }
+ }
+ }
+
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ Intent emergencyIntent = mStatusBar.getEmergencyActionIntent();
+
+ if (emergencyIntent == null) {
+ Log.wtf(StatusBar.TAG, "Couldn't find an app to process the emergency intent.");
+ return;
+ }
+
+ if (isGoingToSleep()) {
+ mStatusBar.setLaunchEmergencyActionOnFinishedGoingToSleep(true);
+ return;
+ }
+
+ if (!mStatusBar.isDeviceInteractive()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:EMERGENCY_GESTURE");
+ }
+ // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
+ // app-side haptic experimentation.
+
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ mStatusBar.startActivityDismissingKeyguard(emergencyIntent,
+ false /* onlyProvisioned */, true /* dismissShade */,
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
+ return;
+ }
+
+ if (!mStatusBar.isDeviceInteractive()) {
+ // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+ // comes on.
+ mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+ }
+
+ if (isWakingUpOrAwake()) {
+ if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ mStatusBarKeyguardViewManager.reset(true /* hide */);
+ }
+ mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+ return;
+ }
+ // We need to defer the emergency action launch until the screen comes on, since otherwise
+ // we will dismiss us too early since we are waiting on an activity to be drawn and
+ // incorrectly get notified because of the screen on event (which resumes and pauses
+ // some activities)
+ mStatusBar.setLaunchEmergencyActionOnFinishedWaking(true);
+ }
+
+ @Override
+ public void onRecentsAnimationStateChanged(boolean running) {
+ mStatusBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
+ }
+
+
+ @Override
+ public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+ AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ boolean barModeChanged = mStatusBar.setAppearance(appearance);
+
+ mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
+ mStatusBar.getBarMode(), navbarColorManagedByIme);
+
+ mStatusBar.updateBubblesVisibility();
+ mStatusBarStateController.setSystemBarAttributes(
+ appearance, behavior, requestedVisibilities, packageName);
+ }
+
+ @Override
+ public void showTransient(int displayId, @InternalInsetsType int[] types) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ if (!containsType(types, ITYPE_STATUS_BAR)) {
+ return;
+ }
+ mStatusBar.showTransientUnchecked();
+ }
+
+ @Override
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
+ int msg = StatusBar.MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
+ mStatusBar.getHandler().removeMessages(msg);
+ mStatusBar.getHandler().obtainMessage(msg, deviceId, 0).sendToTarget();
+ }
+
+ @Override
+ public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
+ mStatusBar.setTopHidesStatusBar(topAppHidesStatusBar);
+ if (!topAppHidesStatusBar && mStatusBar.getWereIconsJustHidden()) {
+ // Immediately update the icon hidden state, since that should only apply if we're
+ // staying fullscreen.
+ mStatusBar.setWereIconsJustHidden(false);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true);
+ }
+ mStatusBar.updateHideIconsForBouncer(true /* animate */);
+ }
+
+ @Override
+ public void setWindowState(
+ int displayId, @StatusBarManager.WindowType int window,
+ @StatusBarManager.WindowVisibleState int state) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ boolean showing = state == WINDOW_STATE_SHOWING;
+ if (mNotificationShadeWindowView != null
+ && window == StatusBarManager.WINDOW_STATUS_BAR
+ && !mStatusBar.isSameStatusBarState(state)) {
+ mStatusBar.setWindowState(state);
+ if (StatusBar.DEBUG_WINDOW_STATE) {
+ Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state));
+ }
+ if (mStatusBar.getStatusBarView() != null) {
+ if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+ mStatusBar.getStatusBarView().collapsePanel(
+ false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */);
+ }
+
+ mStatusBar.updateHideIconsForBouncer(false /* animate */);
+ }
+ }
+
+ mStatusBar.updateBubblesVisibility();
+ }
+
+ @Override
+ public void showAssistDisclosure() {
+ mAssistManager.showDisclosure();
+ }
+
+ @Override
+ public void showPinningEnterExitToast(boolean entering) {
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().showPinningEnterExitToast(entering);
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() {
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().showPinningEscapeToast();
+ }
+ }
+
+ @Override
+ public void showScreenPinningRequest(int taskId) {
+ if (mKeyguardStateController.isShowing()) {
+ // Don't allow apps to trigger this from keyguard.
+ return;
+ }
+ // Show screen pinning request, since this comes from an app, show 'no thanks', button.
+ mStatusBar.showScreenPinningRequest(taskId, true);
+ }
+
+ @Override
+ public void showWirelessChargingAnimation(int batteryLevel) {
+ mStatusBar.showWirelessChargingAnimation(batteryLevel);
+ }
+
+ @Override
+ public void startAssist(Bundle args) {
+ mAssistManager.startAssist(args);
+ }
+
+ @Override
+ public void suppressAmbientDisplay(boolean suppressed) {
+ mDozeServiceHost.setDozeSuppressed(suppressed);
+ }
+
+ @Override
+ public void togglePanel() {
+ if (mStatusBar.isPanelExpanded()) {
+ mShadeController.animateCollapsePanels();
+ } else {
+ animateExpandNotificationsPanel();
+ }
+ }
+
+ @Override
+ public void toggleSplitScreen() {
+ mStatusBar.toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
+ }
+
+ private boolean isGoingToSleep() {
+ return mWakefulnessLifecycle.getWakefulness()
+ == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
+ }
+
+ private boolean isWakingUpOrAwake() {
+ return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
+ || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
+ }
+
+ private void vibrateForCameraGesture() {
+ // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+ mVibratorOptional.ifPresent(
+ v -> v.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES));
+ }
+
+ private static VibrationEffect getCameraGestureVibrationEffect(
+ Optional<Vibrator> vibratorOptional, Resources resources) {
+ if (vibratorOptional.isPresent() && vibratorOptional.get().areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
+ VibrationEffect.Composition.PRIMITIVE_CLICK)) {
+ return VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
+ .compose();
+ }
+ if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) {
+ return VibrationEffect.createWaveform(
+ StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
+ StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
+ /* repeat= */ -1);
+ }
+
+ int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
+ long[] timings = new long[pattern.length];
+ for (int i = 0; i < pattern.length; i++) {
+ timings[i] = pattern[i];
+ }
+ return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
+ }
+}
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/StatusBarDemoMode.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
new file mode 100644
index 0000000..e642b2e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarDemoMode implements DemoMode {
+ private final StatusBar mStatusBar;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final NotificationShadeWindowViewController mNotificationShadeWindowViewController;
+ private final NavigationBarController mNavigationBarController;
+ private final int mDisplayId;
+
+ @Inject
+ StatusBarDemoMode(
+ StatusBar statusBar,
+ NotificationShadeWindowController notificationShadeWindowController,
+ NotificationShadeWindowViewController notificationShadeWindowViewController,
+ NavigationBarController navigationBarController,
+ @DisplayId int displayId) {
+ mStatusBar = statusBar;
+ mNotificationShadeWindowController = notificationShadeWindowController;
+ mNotificationShadeWindowViewController = notificationShadeWindowViewController;
+ mNavigationBarController = navigationBarController;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public List<String> demoCommands() {
+ List<String> s = new ArrayList<>();
+ s.add(DemoMode.COMMAND_BARS);
+ s.add(DemoMode.COMMAND_CLOCK);
+ s.add(DemoMode.COMMAND_OPERATOR);
+ return s;
+ }
+
+ @Override
+ public void onDemoModeStarted() {
+ // Must send this message to any view that we delegate to via dispatchDemoCommandToView
+ dispatchDemoModeStartedToView(R.id.clock);
+ dispatchDemoModeStartedToView(R.id.operator_name);
+ }
+
+ @Override
+ public void onDemoModeFinished() {
+ dispatchDemoModeFinishedToView(R.id.clock);
+ dispatchDemoModeFinishedToView(R.id.operator_name);
+ mStatusBar.checkBarModes();
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, @NonNull Bundle args) {
+ if (command.equals(COMMAND_CLOCK)) {
+ dispatchDemoCommandToView(command, args, R.id.clock);
+ }
+ if (command.equals(COMMAND_BARS)) {
+ String mode = args.getString("mode");
+ int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
+ "translucent".equals(mode) ? MODE_TRANSLUCENT :
+ "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
+ "transparent".equals(mode) ? MODE_TRANSPARENT :
+ "warning".equals(mode) ? MODE_WARNING :
+ -1;
+ if (barMode != -1) {
+ boolean animate = true;
+ if (mNotificationShadeWindowController != null
+ && mNotificationShadeWindowViewController.getBarTransitions() != null) {
+ mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
+ barMode, animate);
+ }
+ mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
+ }
+ }
+ if (command.equals(COMMAND_OPERATOR)) {
+ dispatchDemoCommandToView(command, args, R.id.operator_name);
+ }
+ }
+
+ private void dispatchDemoModeStartedToView(int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).onDemoModeStarted();
+ }
+ }
+
+ //TODO: these should have controllers, and this method should be removed
+ private void dispatchDemoCommandToView(String command, Bundle args, int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
+ }
+ }
+
+ private void dispatchDemoModeFinishedToView(int id) {
+ View statusBarView = mStatusBar.getStatusBarView();
+ if (statusBarView == null) return;
+ View v = statusBarView.findViewById(id);
+ if (v instanceof DemoModeCommandReceiver) {
+ ((DemoModeCommandReceiver) v).onDemoModeFinished();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
new file mode 100644
index 0000000..ca877af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+
+import javax.inject.Inject;
+
+/** Ties the {@link StatusBar} to {@link com.android.systemui.statusbar.policy.HeadsUpManager}. */
+@StatusBarComponent.StatusBarScope
+public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener {
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
+ private final NotificationPanelViewController mNotificationPanelViewController;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final HeadsUpManagerPhone mHeadsUpManager;
+ private final StatusBarStateController mStatusBarStateController;
+ private final NotificationRemoteInputManager mNotificationRemoteInputManager;
+ private final NotificationsController mNotificationsController;
+ private final DozeServiceHost mDozeServiceHost;
+ private final DozeScrimController mDozeScrimController;
+
+ @Inject
+ StatusBarHeadsUpChangeListener(
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarWindowController statusBarWindowController,
+ NotificationPanelViewController notificationPanelViewController,
+ KeyguardBypassController keyguardBypassController,
+ HeadsUpManagerPhone headsUpManager,
+ StatusBarStateController statusBarStateController,
+ NotificationRemoteInputManager notificationRemoteInputManager,
+ NotificationsController notificationsController,
+ DozeServiceHost dozeServiceHost,
+ DozeScrimController dozeScrimController) {
+
+ mNotificationShadeWindowController = notificationShadeWindowController;
+ mStatusBarWindowController = statusBarWindowController;
+ mNotificationPanelViewController = notificationPanelViewController;
+ mKeyguardBypassController = keyguardBypassController;
+ mHeadsUpManager = headsUpManager;
+ mStatusBarStateController = statusBarStateController;
+ mNotificationRemoteInputManager = notificationRemoteInputManager;
+ mNotificationsController = notificationsController;
+ mDozeServiceHost = dozeServiceHost;
+ mDozeScrimController = dozeScrimController;
+ }
+
+ @Override
+ public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+ if (inPinnedMode) {
+ mNotificationShadeWindowController.setHeadsUpShowing(true);
+ mStatusBarWindowController.setForceStatusBarVisible(true);
+ if (mNotificationPanelViewController.isFullyCollapsed()) {
+ // We need to ensure that the touchable region is updated before the
+ //window will be
+ // resized, in order to not catch any touches. A layout will ensure that
+ // onComputeInternalInsets will be called and after that we can
+ //resize the layout. Let's
+ // make sure that the window stays small for one frame until the
+ //touchableRegion is set.
+ mNotificationPanelViewController.getView().requestLayout();
+ mNotificationShadeWindowController.setForceWindowCollapsed(true);
+ mNotificationPanelViewController.getView().post(() -> {
+ mNotificationShadeWindowController.setForceWindowCollapsed(false);
+ });
+ }
+ } else {
+ boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
+ && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+ if (!mNotificationPanelViewController.isFullyCollapsed()
+ || mNotificationPanelViewController.isTracking()
+ || bypassKeyguard) {
+ // We are currently tracking or is open and the shade doesn't need to
+ //be kept
+ // open artificially.
+ mNotificationShadeWindowController.setHeadsUpShowing(false);
+ if (bypassKeyguard) {
+ mStatusBarWindowController.setForceStatusBarVisible(false);
+ }
+ } else {
+ // we need to keep the panel open artificially, let's wait until the
+ //animation
+ // is finished.
+ mHeadsUpManager.setHeadsUpGoingAway(true);
+ mNotificationPanelViewController.runAfterAnimationFinished(() -> {
+ if (!mHeadsUpManager.hasPinnedHeadsUp()) {
+ mNotificationShadeWindowController.setHeadsUpShowing(false);
+ mHeadsUpManager.setHeadsUpGoingAway(false);
+ }
+ mNotificationRemoteInputManager.onPanelCollapsed();
+ });
+ }
+ }
+ }
+
+ @Override
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+ mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
+ if (mStatusBarStateController.isDozing() && isHeadsUp) {
+ entry.setPulseSuppressed(false);
+ mDozeServiceHost.fireNotificationPulse(entry);
+ if (mDozeServiceHost.isPulsing()) {
+ mDozeScrimController.cancelPendingPulseTimeout();
+ }
+ }
+ if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
+ // There are no longer any notifications to show. We should end the
+ //pulse now.
+ mDozeScrimController.pulseOutNow();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 2c75534..48fe774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -35,10 +35,11 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
@@ -50,6 +51,8 @@
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
public interface StatusBarIconController {
/**
@@ -213,6 +216,20 @@
icons.setColor(mColor);
return icons;
}
+
+ @SysUISingleton
+ public static class Factory {
+ private final FeatureFlags mFeatureFlags;
+
+ @Inject
+ public Factory(FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
+ }
+
+ public TintedIconManager create(ViewGroup group) {
+ return new TintedIconManager(group, mFeatureFlags);
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 75900a2..9d1c1e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -23,6 +23,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.view.ViewGroup;
import com.android.internal.statusbar.StatusBarIcon;
@@ -88,6 +89,13 @@
/** */
@Override
public void addIconGroup(IconManager group) {
+ for (IconManager existingIconManager : mIconGroups) {
+ if (existingIconManager.mGroup == group.mGroup) {
+ Log.e(TAG, "Adding new IconManager for the same ViewGroup. This could cause "
+ + "unexpected results.");
+ }
+ }
+
mIconGroups.add(group);
List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) {
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..8873fbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -52,15 +52,14 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationClickNotifier;
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/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index fe52281..7136432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -25,7 +25,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
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/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index 4fab226..d408c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -24,6 +24,9 @@
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
+import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks;
+import com.android.systemui.statusbar.phone.StatusBarDemoMode;
+import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.lang.annotation.Documented;
@@ -89,6 +92,24 @@
AuthRippleController getAuthRippleController();
/**
+ * Creates a StatusBarDemoMode.
+ */
+ @StatusBarScope
+ StatusBarDemoMode getStatusBarDemoMode();
+
+ /**
+ * Creates a StatusBarHeadsUpChangeListener.
+ */
+ @StatusBarScope
+ StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
+
+ /**
+ * Creates a StatusBarCommandQueueCallbacks.
+ */
+ @StatusBarScope
+ StatusBarCommandQueueCallbacks getStatusBarCommandQueueCallbacks();
+
+ /**
* Creates a SplitShadeHeaderController.
*/
@StatusBarScope
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..7ad0e7f 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
@@ -18,18 +18,16 @@
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+import android.app.WallpaperManager;
import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.util.DisplayMetrics;
-import androidx.annotation.Nullable;
-
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
@@ -37,7 +35,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -49,7 +47,6 @@
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -61,8 +58,6 @@
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -80,7 +75,6 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LightsOutNotifController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -89,10 +83,10 @@
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;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
@@ -102,11 +96,12 @@
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-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.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -137,7 +132,6 @@
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -148,7 +142,6 @@
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
- RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -167,19 +160,16 @@
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
- VibratorHelper vibratorHelper,
Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
- AccessibilityFloatingMenuController accessibilityFloatingMenuController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
DozeParameters dozeParameters,
ScrimController scrimController,
- @Nullable KeyguardLiftController keyguardLiftController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
DozeServiceHost dozeServiceHost,
@@ -208,17 +198,19 @@
KeyguardIndicationController keyguardIndicationController,
DemoModeController demoModeController,
Lazy<NotificationShadeDepthController> notificationShadeDepthController,
- DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
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,
+ WallpaperManager wallpaperManager,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
Optional<StartingSurface> startingSurfaceOptional) {
return new StatusBar(
@@ -227,7 +219,6 @@
lightBarController,
autoHideController,
keyguardUpdateMonitor,
- signalPolicy,
pulseExpansionHandler,
notificationWakeUpCoordinator,
keyguardBypassController,
@@ -238,7 +229,6 @@
falsingManager,
falsingCollector,
broadcastDispatcher,
- remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
notificationInterruptStateProvider,
@@ -257,19 +247,16 @@
screenLifecycle,
wakefulnessLifecycle,
statusBarStateController,
- vibratorHelper,
bubblesManagerOptional,
bubblesOptional,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
- accessibilityFloatingMenuController,
assistManagerLazy,
configurationController,
notificationShadeWindowController,
dozeParameters,
scrimController,
- keyguardLiftController,
lockscreenWallpaperLazy,
biometricUnlockControllerLazy,
dozeServiceHost,
@@ -295,19 +282,21 @@
userInfoControllerImpl,
phoneStatusBarPolicy,
keyguardIndicationController,
- dismissCallbackRegistry,
demoModeController,
notificationShadeDepthController,
statusBarTouchableRegionManager,
notificationIconAreaController,
brightnessSliderFactory,
- chargingRippleAnimationController,
+ unfoldTransitionConfig,
+ unfoldLightRevealOverlayAnimation,
ongoingCallController,
animationScheduler,
locationPublisher,
+ statusBarIconController,
transitionController,
featureFlags,
keyguardUnlockAnimationController,
+ wallpaperManager,
unlockedScreenOffAnimationController,
startingSurfaceOptional);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index d691dca..0e83eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -21,6 +21,7 @@
import com.android.keyguard.LockIconView;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -73,6 +74,13 @@
/** */
@Provides
@StatusBarComponent.StatusBarScope
+ static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) {
+ return view.findViewById(R.id.batteryRemainingIcon);
+ }
+
+ /** */
+ @Provides
+ @StatusBarComponent.StatusBarScope
public static TapAgainView getTapAgainView(NotificationPanelView npv) {
return npv.getTapAgainView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 16fa5da..1db6ce4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -24,7 +24,6 @@
import android.content.Intent
import android.util.Log
import android.view.View
-import android.widget.Chronometer
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.R
@@ -32,7 +31,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -130,7 +129,6 @@
}
}
-
/**
* Called when the chip's visibility may have changed.
*
@@ -220,7 +218,11 @@
uidObserver = object : IUidObserver.Stub() {
override fun onUidStateChanged(
- uid: Int, procState: Int, procStateSeq: Long, capability: Int) {
+ uid: Int,
+ procState: Int,
+ procStateSeq: Long,
+ capability: Int
+ ) {
if (uid == currentCallNotificationInfo.uid) {
val oldIsCallAppVisible = isCallAppVisible
isCallAppVisible = isProcessVisibleToUser(procState)
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 4ca1f60..d80fa12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
-import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.SimpleClock;
@@ -286,7 +285,6 @@
private final Context mContext;
private final @Nullable WifiManager mWifiManager;
private final ConnectivityManager mConnectivityManager;
- private final NetworkScoreManager mNetworkScoreManager;
private final Handler mMainHandler;
private final Handler mWorkerHandler;
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@@ -301,14 +299,12 @@
Context context,
@Nullable WifiManager wifiManager,
ConnectivityManager connectivityManager,
- NetworkScoreManager networkScoreManager,
@Main Handler mainHandler,
@Background Handler workerHandler
) {
mContext = context;
mWifiManager = wifiManager;
mConnectivityManager = connectivityManager;
- mNetworkScoreManager = networkScoreManager;
mMainHandler = mainHandler;
mWorkerHandler = workerHandler;
}
@@ -332,7 +328,6 @@
mContext,
mWifiManager,
mConnectivityManager,
- mNetworkScoreManager,
mMainHandler,
mWorkerHandler,
mClock,
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/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
new file mode 100644
index 0000000..fbfa5e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.android.systemui.statusbar.policy.DevicePostureController.Callback;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Listener for device posture changes. This can be used to query the current posture, or register
+ * for events when it changes.
+ */
+public interface DevicePostureController extends CallbackController<Callback> {
+ @IntDef(prefix = {"DEVICE_POSTURE_"}, value = {
+ DEVICE_POSTURE_UNKNOWN,
+ DEVICE_POSTURE_CLOSED,
+ DEVICE_POSTURE_HALF_OPENED,
+ DEVICE_POSTURE_OPENED,
+ DEVICE_POSTURE_FLIPPED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DevicePostureInt {}
+
+ // NOTE: These constants **must** match those defined for Jetpack Sidecar. This is because we
+ // use the Device State -> Jetpack Posture map in DevicePostureControllerImpl to translate
+ // between the two.
+ int DEVICE_POSTURE_UNKNOWN = 0;
+ int DEVICE_POSTURE_CLOSED = 1;
+ int DEVICE_POSTURE_HALF_OPENED = 2;
+ int DEVICE_POSTURE_OPENED = 3;
+ int DEVICE_POSTURE_FLIPPED = 4;
+
+ /** Return the current device posture. */
+ @DevicePostureInt int getDevicePosture();
+
+ /** Callback to be notified about device posture changes. */
+ interface Callback {
+ /** Called when the posture changes. */
+ void onPostureChanged(@DevicePostureInt int posture);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
new file mode 100644
index 0000000..8471e0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.util.SparseIntArray;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
+@SysUISingleton
+public class DevicePostureControllerImpl implements DevicePostureController {
+ private final List<Callback> mListeners = new ArrayList<>();
+ private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
+
+ private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
+
+ @Inject
+ public DevicePostureControllerImpl(
+ Context context, DeviceStateManager deviceStateManager, @Main Executor executor) {
+ // Most of this is borrowed from WindowManager/Jetpack/DeviceStateManagerPostureProducer.
+ // Using the sidecar/extension libraries directly brings in a new dependency that it'd be
+ // good to avoid (along with the fact that sidecar is deprecated, and extensions isn't fully
+ // ready yet), and we'd have to make our own layer over the sidecar library anyway to easily
+ // allow the implementation to change, so it was easier to just interface with
+ // DeviceStateManager directly.
+ String[] deviceStatePosturePairs = context.getResources()
+ .getStringArray(R.array.config_device_state_postures);
+ for (String deviceStatePosturePair : deviceStatePosturePairs) {
+ String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
+ if (deviceStatePostureMapping.length != 2) {
+ continue;
+ }
+
+ int deviceState;
+ int posture;
+ try {
+ deviceState = Integer.parseInt(deviceStatePostureMapping[0]);
+ posture = Integer.parseInt(deviceStatePostureMapping[1]);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+
+ mDeviceStateToPostureMap.put(deviceState, posture);
+ }
+
+ deviceStateManager.registerCallback(executor, state -> {
+ mCurrentDevicePosture =
+ mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+
+ mListeners.forEach(l -> l.onPostureChanged(mCurrentDevicePosture));
+ });
+ }
+
+ @Override
+ public void addCallback(@NonNull Callback listener) {
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void removeCallback(@NonNull Callback listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public int getDevicePosture() {
+ return mCurrentDevicePosture;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
new file mode 100644
index 0000000..41cacf5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
+
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
+import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+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.wrapper.RotationPolicyWrapper;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Handles reading and writing of rotation lock settings per device state, as well as setting
+ * the rotation lock when device state changes.
+ **/
+@SysUISingleton
+public final class DeviceStateRotationLockSettingController implements Listenable,
+ RotationLockController.RotationLockControllerCallback {
+
+ private static final String TAG = "DSRotateLockSettingCon";
+
+ private static final String SEPARATOR_REGEX = ":";
+
+ private final SecureSettings mSecureSettings;
+ private final RotationPolicyWrapper mRotationPolicyWrapper;
+ private final DeviceStateManager mDeviceStateManager;
+ private final Executor mMainExecutor;
+ private final String[] mDeviceStateRotationLockDefaults;
+
+ private SparseIntArray mDeviceStateRotationLockSettings;
+ // TODO(b/183001527): Add API to query current device state and initialize this.
+ private int mDeviceState = -1;
+ @Nullable
+ private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+
+ @Inject
+ public DeviceStateRotationLockSettingController(
+ SecureSettings secureSettings,
+ RotationPolicyWrapper rotationPolicyWrapper,
+ DeviceStateManager deviceStateManager,
+ @Main Executor executor,
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+ ) {
+ mSecureSettings = secureSettings;
+ mRotationPolicyWrapper = rotationPolicyWrapper;
+ mDeviceStateManager = deviceStateManager;
+ mMainExecutor = executor;
+ mDeviceStateRotationLockDefaults = deviceStateRotationLockDefaults;
+ }
+
+ /**
+ * Loads the settings from storage.
+ */
+ public void initialize() {
+ String serializedSetting =
+ mSecureSettings.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT);
+ if (TextUtils.isEmpty(serializedSetting)) {
+ // No settings saved, we should load the defaults and persist them.
+ fallbackOnDefaults();
+ return;
+ }
+ String[] values = serializedSetting.split(SEPARATOR_REGEX);
+ if (values.length % 2 != 0) {
+ // Each entry should be a key/value pair, so this is corrupt.
+ Log.wtf(TAG, "Can't deserialize saved settings, falling back on defaults");
+ fallbackOnDefaults();
+ return;
+ }
+ mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+ int key;
+ int value;
+
+ for (int i = 0; i < values.length - 1; ) {
+ try {
+ key = Integer.parseInt(values[i++]);
+ value = Integer.parseInt(values[i++]);
+ mDeviceStateRotationLockSettings.put(key, value);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Error deserializing one of the saved settings", e);
+ fallbackOnDefaults();
+ return;
+ }
+ }
+ }
+
+ private void fallbackOnDefaults() {
+ loadDefaults();
+ persistSettings();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ // Note that this is called once with the initial state of the device, even if there
+ // is no user action.
+ mDeviceStateCallback = this::updateDeviceState;
+ mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
+ } else {
+ if (mDeviceStateCallback != null) {
+ mDeviceStateManager.unregisterCallback(mDeviceStateCallback);
+ }
+ }
+ }
+
+ @Override
+ public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+ if (mDeviceState == -1) {
+ Log.wtf(TAG, "Device state was not initialized.");
+ return;
+ }
+
+ if (rotationLocked == isRotationLockedForCurrentState()) {
+ Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
+ return;
+ }
+
+ saveNewRotationLockSetting(rotationLocked);
+ }
+
+ private void saveNewRotationLockSetting(boolean isRotationLocked) {
+ Log.v(TAG, "saveNewRotationLockSetting [state=" + mDeviceState + "] [isRotationLocked="
+ + isRotationLocked + "]");
+
+ mDeviceStateRotationLockSettings.put(mDeviceState,
+ isRotationLocked
+ ? DEVICE_STATE_ROTATION_LOCK_LOCKED
+ : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ persistSettings();
+ }
+
+ private boolean isRotationLockedForCurrentState() {
+ return mDeviceStateRotationLockSettings.get(mDeviceState,
+ DEVICE_STATE_ROTATION_LOCK_IGNORED) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+ }
+
+ private void updateDeviceState(int state) {
+ Log.v(TAG, "updateDeviceState [state=" + state + "]");
+ if (mDeviceState == state) {
+ return;
+ }
+
+ int rotationLockSetting =
+ mDeviceStateRotationLockSettings.get(state, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+ // We won't handle this device state. The same rotation lock setting as before should
+ // apply and any changes to the rotation lock setting will be written for the previous
+ // valid device state.
+ Log.v(TAG, "Ignoring new device state: " + state);
+ return;
+ }
+
+ // Accept the new state
+ mDeviceState = state;
+
+ // Update the rotation lock setting if needed for this new device state
+ boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+ if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
+ mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
+ }
+ }
+
+ private void persistSettings() {
+ if (mDeviceStateRotationLockSettings.size() == 0) {
+ mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"", UserHandle.USER_CURRENT);
+ return;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(mDeviceStateRotationLockSettings.keyAt(0))
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.valueAt(0));
+
+ for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+ stringBuilder
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.keyAt(i))
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.valueAt(i));
+ }
+ mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ stringBuilder.toString(), UserHandle.USER_CURRENT);
+ }
+
+ private void loadDefaults() {
+ if (mDeviceStateRotationLockDefaults.length == 0) {
+ Log.w(TAG, "Empty default settings");
+ mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */0);
+ return;
+ }
+ mDeviceStateRotationLockSettings =
+ new SparseIntArray(mDeviceStateRotationLockDefaults.length);
+ for (String serializedDefault : mDeviceStateRotationLockDefaults) {
+ String[] entry = serializedDefault.split(SEPARATOR_REGEX);
+ try {
+ int key = Integer.parseInt(entry[0]);
+ int value = Integer.parseInt(entry[1]);
+ mDeviceStateRotationLockSettings.put(key, value);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Error deserializing default settings", e);
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 43781f3..3490e15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -57,7 +57,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
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 52c37a9..d6ac6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -71,10 +71,10 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 53d68d0..67f5364 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -16,36 +16,54 @@
package com.android.systemui.statusbar.policy;
-import android.content.Context;
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
import android.os.UserHandle;
import androidx.annotation.NonNull;
-import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
+import javax.inject.Named;
/** Platform implementation of the rotation lock controller. **/
@SysUISingleton
public final class RotationLockControllerImpl implements RotationLockController {
- private final Context mContext;
private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
- new CopyOnWriteArrayList<RotationLockControllerCallback>();
+ new CopyOnWriteArrayList<>();
- private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
- new RotationPolicy.RotationPolicyListener() {
+ private final RotationPolicyListener mRotationPolicyListener =
+ new RotationPolicyListener() {
@Override
public void onChange() {
notifyChanged();
}
};
+ private final RotationPolicyWrapper mRotationPolicy;
+ private final DeviceStateRotationLockSettingController
+ mDeviceStateRotationLockSettingController;
+ private final boolean mIsPerDeviceStateRotationLockEnabled;
+
@Inject
- public RotationLockControllerImpl(Context context) {
- mContext = context;
+ public RotationLockControllerImpl(
+ RotationPolicyWrapper rotationPolicyWrapper,
+ DeviceStateRotationLockSettingController deviceStateRotationLockSettingController,
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+ ) {
+ mRotationPolicy = rotationPolicyWrapper;
+ mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
+ mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
+ if (mIsPerDeviceStateRotationLockEnabled) {
+ deviceStateRotationLockSettingController.initialize();
+ mCallbacks.add(mDeviceStateRotationLockSettingController);
+ }
+
setListening(true);
}
@@ -61,32 +79,35 @@
}
public int getRotationLockOrientation() {
- return RotationPolicy.getRotationLockOrientation(mContext);
+ return mRotationPolicy.getRotationLockOrientation();
}
public boolean isRotationLocked() {
- return RotationPolicy.isRotationLocked(mContext);
+ return mRotationPolicy.isRotationLocked();
}
public void setRotationLocked(boolean locked) {
- RotationPolicy.setRotationLock(mContext, locked);
+ mRotationPolicy.setRotationLock(locked);
}
public void setRotationLockedAtAngle(boolean locked, int rotation){
- RotationPolicy.setRotationLockAtAngle(mContext, locked, rotation);
+ mRotationPolicy.setRotationLockAtAngle(locked, rotation);
}
public boolean isRotationLockAffordanceVisible() {
- return RotationPolicy.isRotationLockToggleVisible(mContext);
+ return mRotationPolicy.isRotationLockToggleVisible();
}
@Override
public void setListening(boolean listening) {
if (listening) {
- RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
+ mRotationPolicy.registerRotationPolicyListener(mRotationPolicyListener,
UserHandle.USER_ALL);
} else {
- RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+ mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener);
+ }
+ if (mIsPerDeviceStateRotationLockEnabled) {
+ mDeviceStateRotationLockSettingController.setListening(listening);
}
}
@@ -97,7 +118,7 @@
}
private void notifyChanged(RotationLockControllerCallback callback) {
- callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
- RotationPolicy.isRotationLockToggleVisible(mContext));
+ callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
+ mRotationPolicy.isRotationLockToggleVisible());
}
}
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..8f1a578 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -65,8 +65,8 @@
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
@@ -138,8 +138,9 @@
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
private final UiEventLogger mUiEventLogger;
public final DetailAdapter mUserDetailAdapter;
- private final Executor mUiBgExecutor;
+ private final Executor mBgExecutor;
private final boolean mGuestUserAutoCreated;
+ private final AtomicBoolean mGuestIsResetting;
private final AtomicBoolean mGuestCreationScheduled;
private FalsingManager mFalsingManager;
@@ -157,7 +158,7 @@
IActivityTaskManager activityTaskManager,
UserDetailAdapter userDetailAdapter,
SecureSettings secureSettings,
- @UiBackground Executor uiBgExecutor) {
+ @Background Executor bgExecutor) {
mContext = context;
mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
@@ -168,12 +169,13 @@
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
this, mUserTracker, mUiEventLogger, secureSettings);
mUserDetailAdapter = userDetailAdapter;
- mUiBgExecutor = uiBgExecutor;
+ mBgExecutor = bgExecutor;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
}
mGuestUserAutoCreated = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_guestUserAutoCreated);
+ mGuestIsResetting = new AtomicBoolean();
mGuestCreationScheduled = new AtomicBoolean();
mKeyguardStateController = keyguardStateController;
mHandler = handler;
@@ -198,6 +200,7 @@
PERMISSION_SELF, null /* scheduler */);
mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
public void onChange(boolean selfChange) {
mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
@@ -323,7 +326,20 @@
boolean createIsRestricted = !addUsersWhenLocked;
if (guestRecord == null) {
- if (canCreateGuest) {
+ if (mGuestUserAutoCreated) {
+ // If mGuestIsResetting=true, the switch should be disabled since
+ // we will just use it as an indicator for "Resetting guest...".
+ // Otherwise, default to canSwitchUsers.
+ boolean isSwitchToGuestEnabled =
+ !mGuestIsResetting.get() && canSwitchUsers;
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, false /* isRestricted */,
+ isSwitchToGuestEnabled);
+ // Don't call checkIfAddUserDisallowedByAdminOnly if
+ // config_guestUserAutoCreated=true.
+ records.add(guestRecord);
+ } else if (canCreateGuest) {
guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
false /* isAddUser */, createIsRestricted, canSwitchUsers);
@@ -562,6 +578,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);
@@ -679,8 +702,7 @@
mUserManager.removeUser(currentUser.id);
} else {
if (mGuestUserAutoCreated) {
- // TODO(b/191067027): Move guest recreation to system_server
- scheduleGuestCreation();
+ mGuestIsResetting.set(true);
}
switchToUserId(targetUserId);
mUserManager.removeUser(currentUser.id);
@@ -696,12 +718,16 @@
return;
}
- mUiBgExecutor.execute(() -> {
+ mBgExecutor.execute(() -> {
int newGuestId = createGuest();
+ mGuestCreationScheduled.set(false);
+ mGuestIsResetting.set(false);
if (newGuestId == UserHandle.USER_NULL) {
Log.w(TAG, "Could not create new guest while exiting existing guest");
+ // Refresh users so that we still display "Guest" if
+ // config_guestUserAutoCreated=true
+ refreshUsers(UserHandle.USER_NULL);
}
- mGuestCreationScheduled.set(false);
});
}
@@ -804,12 +830,25 @@
? com.android.settingslib.R.string.guest_reset_guest
: com.android.settingslib.R.string.guest_exit_guest);
} else {
- // If config_guestUserAutoCreated, always show guest nickname instead of "Add
- // guest" to make it seem as though the device always has a guest ready for use
- return context.getString(
- item.info == null && !mController.mGuestUserAutoCreated
- ? com.android.settingslib.R.string.guest_new_guest
- : com.android.settingslib.R.string.guest_nickname);
+ if (item.info != null) {
+ return context.getString(com.android.settingslib.R.string.guest_nickname);
+ } else {
+ if (mController.mGuestUserAutoCreated) {
+ // If mGuestIsResetting=true, we expect the guest user to be created
+ // shortly, so display a "Resetting guest..." as an indicator that we
+ // are busy. Otherwise, if mGuestIsResetting=false, we probably failed
+ // to create a guest at some point. In this case, always show guest
+ // nickname instead of "Add guest" to make it seem as though the device
+ // always has a guest ready for use.
+ return context.getString(
+ mController.mGuestIsResetting.get()
+ ? com.android.settingslib.R.string.guest_resetting
+ : com.android.settingslib.R.string.guest_nickname);
+ } else {
+ return context.getString(
+ com.android.settingslib.R.string.guest_new_guest);
+ }
+ }
}
} else if (item.isAddUser) {
return context.getString(R.string.user_add_user);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index f8e3647..fc19564 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -36,7 +36,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.wifi.WifiStatusTracker;
import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 9fb0453..1eec639 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.policy.dagger;
+import android.content.res.Resources;
import android.os.UserManager;
+import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.UserTracker;
@@ -28,6 +30,8 @@
import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.statusbar.policy.DevicePostureControllerImpl;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -55,6 +59,8 @@
import java.util.concurrent.Executor;
+import javax.inject.Named;
+
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -63,6 +69,9 @@
/** Dagger Module for code in the statusbar.policy package. */
@Module
public interface StatusBarPolicyModule {
+
+ String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
+
/** */
@Binds
BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);
@@ -130,6 +139,11 @@
AccessPointControllerImpl accessPointControllerImpl);
/** */
+ @Binds
+ DevicePostureController provideDevicePostureController(
+ DevicePostureControllerImpl devicePostureControllerImpl);
+
+ /** */
@SysUISingleton
@Provides
static AccessPointControllerImpl provideAccessPointControllerImpl(
@@ -147,4 +161,14 @@
controller.init();
return controller;
}
+
+ /**
+ * Default values for per-device state rotation lock settings.
+ */
+ @Provides
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS)
+ static String[] providesDeviceStateRotationLockDefaults(@Main Resources resources) {
+ return resources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults);
+ }
}
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/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 9355244..cfd82f5 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -57,9 +57,9 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index df889f2..3525100 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -39,6 +39,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
@@ -81,6 +82,7 @@
* overridden by the System UI implementation.
*/
@Module(includes = {
+ PowerModule.class,
QSModule.class
},
subcomponents = {
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/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 0dd5788..32bbe1c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -110,6 +110,16 @@
}
/**
+ * Destroys this controller so that it never receives view attach and detach events again.
+ * Does nothing if the view is null.
+ */
+ public void destroy() {
+ if (mView != null) {
+ mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
+ }
+ }
+
+ /**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
protected abstract void onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
index cdfa145..981bf01 100644
--- a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
@@ -18,12 +18,15 @@
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.RingerModeTrackerImpl;
+import com.android.systemui.util.wrapper.UtilWrapperModule;
import dagger.Binds;
import dagger.Module;
/** Dagger Module for code in the util package. */
-@Module
+@Module(includes = {
+ UtilWrapperModule.class
+ })
public interface UtilModule {
/** */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 19ed284..b38fc77 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -281,18 +281,24 @@
mLastPrimaryEvent = event;
- if (event.getBelow() && mSecondaryThresholdSensor.isLoaded()) {
- logDebug("Primary sensor is near. Checking secondary.");
+ if (mSecondarySafe && mSecondaryThresholdSensor.isLoaded()) {
+ logDebug("Primary sensor reported " + (event.getBelow() ? "near" : "far")
+ + ". Checking secondary.");
if (mCancelSecondaryRunnable == null) {
mSecondaryThresholdSensor.resume();
}
- } else {
- if (!mSecondaryThresholdSensor.isLoaded()) {
- logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
- } else {
- logDebug("Primary sensor event: " + event.getBelow() + ".");
- }
+ return;
+ }
+
+ if (!mSecondaryThresholdSensor.isLoaded()) {
+ logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
onSensorEvent(event);
+ } else if (event.getBelow()) {
+ logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
+ if (mCancelSecondaryRunnable != null) {
+ mCancelSecondaryRunnable.run();
+ }
+ mSecondaryThresholdSensor.resume();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
new file mode 100644
index 0000000..2a0cc7d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.util.wrapper
+
+import android.content.Context
+import com.android.internal.view.RotationPolicy
+import com.android.internal.view.RotationPolicy.RotationPolicyListener
+import javax.inject.Inject
+
+/**
+ * Testable wrapper interface around RotationPolicy {link com.android.internal.view.RotationPolicy}
+ */
+interface RotationPolicyWrapper {
+ fun setRotationLock(enabled: Boolean)
+ fun setRotationLockAtAngle(enabled: Boolean, rotation: Int)
+ fun getRotationLockOrientation(): Int
+ fun isRotationLockToggleVisible(): Boolean
+ fun isRotationLocked(): Boolean
+ fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int)
+ fun unregisterRotationPolicyListener(listener: RotationPolicyListener)
+}
+
+class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) :
+ RotationPolicyWrapper {
+
+ override fun setRotationLock(enabled: Boolean) {
+ RotationPolicy.setRotationLock(context, enabled)
+ }
+
+ override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int) {
+ RotationPolicy.setRotationLockAtAngle(context, enabled, rotation)
+ }
+
+ override fun getRotationLockOrientation(): Int =
+ RotationPolicy.getRotationLockOrientation(context)
+
+ override fun isRotationLockToggleVisible(): Boolean =
+ RotationPolicy.isRotationLockToggleVisible(context)
+
+ override fun isRotationLocked(): Boolean =
+ RotationPolicy.isRotationLocked(context)
+
+ override fun registerRotationPolicyListener(
+ listener: RotationPolicyListener,
+ userHandle: Int
+ ) {
+ RotationPolicy.registerRotationPolicyListener(context, listener, userHandle)
+ }
+
+ override fun unregisterRotationPolicyListener(listener: RotationPolicyListener) {
+ RotationPolicy.unregisterRotationPolicyListener(context, listener)
+ }
+}
diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
similarity index 60%
copy from core/java/com/android/internal/view/InputBindResult.aidl
copy to packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
index 7ff5c4e..7e3aa27 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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.
@@ -14,6 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package com.android.systemui.util.wrapper
-parcelable InputBindResult;
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+
+@Module
+abstract class UtilWrapperModule {
+
+ @Binds
+ @SysUISingleton
+ abstract fun bindRotationPolicyWrapper(impl: RotationPolicyWrapperImpl): RotationPolicyWrapper
+}
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/src/com/android/systemui/wallet/ui/WalletCardCarousel.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
index 1e1b459..77fd2e8 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
@@ -190,6 +190,15 @@
}
/**
+ * Sets the adapter again in the RecyclerView, updating the ViewHolders children's layout.
+ * This is needed when changing the state of the device (eg fold/unfold) so the ViewHolders are
+ * recreated.
+ */
+ void resetAdapter() {
+ setAdapter(mWalletCardCarouselAdapter);
+ }
+
+ /**
* Returns true if the data set is changed.
*/
boolean setData(List<WalletCardViewInfo> data, int selectedIndex, boolean hasLockStateChanged) {
@@ -376,8 +385,8 @@
CardView cardView = viewHolder.mCardView;
cardView.setRadius(mCornerRadiusPx);
ViewGroup.LayoutParams layoutParams = cardView.getLayoutParams();
- layoutParams.width = mCardWidthPx;
- layoutParams.height = mCardHeightPx;
+ layoutParams.width = getCardWidthPx();
+ layoutParams.height = getCardHeightPx();
view.setTag(viewHolder);
return viewHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 420f84a..9b2702f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -99,17 +99,13 @@
mCardCarousel.setExpectedViewWidth(getWidth());
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- updateViewForOrientation(newConfig.orientation);
- }
-
private void updateViewForOrientation(@Configuration.Orientation int orientation) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
renderViewPortrait();
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
renderViewLandscape();
}
+ mCardCarousel.resetAdapter(); // necessary to update cards width
ViewGroup.LayoutParams params = mCardCarouselContainer.getLayoutParams();
if (params instanceof MarginLayoutParams) {
((MarginLayoutParams) params).topMargin =
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index a29a638..d3581a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -50,7 +50,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -61,11 +60,10 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
@@ -80,7 +78,6 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -118,7 +115,6 @@
private final NotifPipeline mNotifPipeline;
private final Executor mSysuiMainExecutor;
- private ScrimView mBubbleScrim;
private final Bubbles.SysuiProxy mSysuiProxy;
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
@@ -193,12 +189,6 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE))
: statusBarService;
- mBubbleScrim = new ScrimView(mContext);
- mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- mBubbles.setBubbleScrim(mBubbleScrim, (executor, looper) -> {
- mBubbleScrim.setExecutor(executor, looper);
- });
-
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
setupNotifPipeline();
} else {
@@ -603,15 +593,6 @@
}
/**
- * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
- * since we want the scrim's appearance and behavior to be identical to that of the notification
- * shade scrim.
- */
- public ScrimView getScrimForBubble() {
- return mBubbleScrim;
- }
-
- /**
* We intercept notification entries (including group summaries) dismissed by the user when
* there is an active bubble associated with it. We do this so that developers can still
* cancel it (and hence the bubbles associated with it).
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f2db4f1..db965db 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -242,6 +242,11 @@
void initSplitScreen(SplitScreen splitScreen) {
mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ splitScreen.onKeyguardVisibilityChanged(showing);
+ }
+
+ @Override
public void onKeyguardOccludedChanged(boolean occluded) {
splitScreen.onKeyguardOccludedChanged(occluded);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index fc0214a..d3557d4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -86,8 +86,8 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -513,7 +513,7 @@
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).isHardwareDetected();
verify(mFaceManager).hasEnrolledTemplates(anyInt());
}
@@ -523,7 +523,7 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -533,7 +533,8 @@
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -545,7 +546,8 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -568,13 +570,14 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
// Stop scanning when bouncer becomes visible
setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
mKeyguardUpdateMonitor.requestFaceAuth(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -582,7 +585,7 @@
mKeyguardUpdateMonitor.setKeyguardOccluded(true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -594,7 +597,7 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -604,7 +607,8 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -615,7 +619,8 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -626,7 +631,7 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -638,7 +643,8 @@
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -754,6 +760,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/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 14f112b..cc35a8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -196,7 +196,7 @@
return RemoteAnimationTarget(
0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
- taskInfo
+ taskInfo, false
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index 5cd7810..e478b1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -48,9 +47,9 @@
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -78,14 +77,16 @@
@Mock private TextView mIndicatorView;
@Mock private ImageView mIconView;
@Mock private View mIconHolderView;
- @Mock private AuthBiometricFaceView.IconController mIconController;
+ @Mock private AuthBiometricFaceView.IconController mFaceIconController;
+ @Mock private AuthBiometricFaceToFingerprintView.UdfpsIconController mUdfpsIconController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceToFpView = new TestableView(mContext);
- mFaceToFpView.mIconController = mIconController;
+ mFaceToFpView.mFaceIconController = mFaceIconController;
+ mFaceToFpView.mUdfpsIconController = mUdfpsIconController;
mFaceToFpView.setCallback(mCallback);
mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -99,20 +100,23 @@
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
- verify(mFaceToFpView.mIconController).updateState(
+ verify(mFaceToFpView.mFaceIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
}
@@ -120,21 +124,22 @@
@Test
public void testStateUpdated_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
- mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
- InOrder order = inOrder(mFaceToFpView.mIconController);
- order.verify(mFaceToFpView.mIconController).updateState(
+ verify(mFaceToFpView.mFaceIconController).deactivate();
+ verify(mFaceToFpView.mUdfpsIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
- order.verify(mFaceToFpView.mIconController).updateState(
+ verify(mConfirmButton).setVisibility(eq(View.GONE));
+
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+
+ verify(mFaceToFpView.mUdfpsIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-
- verify(mConfirmButton).setVisibility(eq(View.GONE));
}
@Test
@@ -163,6 +168,7 @@
}
@Test
+ @Ignore("flaky, b/189031816")
public void testModeUpdated_onSoftError_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
@@ -172,10 +178,14 @@
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
- assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+ // First we enter the error state, since we need to show the error animation/text. The
+ // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
+ @Ignore("flaky, b/189031816")
public void testModeUpdated_onHardError_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onError(TYPE_FACE, "oh no!");
@@ -185,13 +195,16 @@
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
- assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+ // First we enter the error state, since we need to show the error animation/text. The
+ // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
public void testFingerprintOnlyStartsOnFirstError() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.onDialogAnimatedIn();
@@ -260,11 +273,6 @@
protected int getDelayAfterAuthenticatedDurationMs() {
return 0;
}
-
- @Override
- protected IconController createUdfpsIconController() {
- return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
- }
}
private class MockInjector extends AuthBiometricView.Injector {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
index 043bd5c..b93381d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
@@ -62,7 +62,7 @@
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceView = new TestableFaceView(mContext);
- mFaceView.mIconController = mock(TestableFaceView.TestableIconController.class);
+ mFaceView.mFaceIconController = mock(TestableFaceView.TestableIconController.class);
mFaceView.setCallback(mCallback);
mFaceView.mNegativeButton = mNegativeButton;
@@ -78,18 +78,18 @@
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceView.onDialogAnimatedIn();
- verify(mFaceView.mIconController)
+ verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATING);
- verify(mFaceView.mIconController)
+ verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
- verify(mFaceView.mIconController).updateState(
+ verify(mFaceView.mFaceIconController).updateState(
eq(AuthBiometricFaceView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceView.STATE_AUTHENTICATED));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index bd518ff..f8e38e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -199,6 +200,7 @@
}
@Test
+ @Ignore("flaky, b/189031816")
public void testError_sendsActionError() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
final String testError = "testError";
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..9098e44 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;
@@ -26,6 +24,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
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;
@@ -33,11 +32,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;
@@ -62,6 +63,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.Execution;
import com.android.systemui.util.concurrency.FakeExecution;
@@ -139,6 +141,12 @@
private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private DisplayManager mDisplayManager;
+ @Mock
+ private Handler mHandler;
+ @Mock
+ private ConfigurationController mConfigurationController;
private FakeExecutor mFgExecutor;
@@ -146,6 +154,10 @@
@Mock
private UdfpsView mUdfpsView;
@Mock
+ private UdfpsEnrollView mEnrollView;
+ @Mock
+ private UdfpsKeyguardView mKeyguardView;
+ @Mock
private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
@Mock
private TypedArray mBrightnessValues;
@@ -167,7 +179,13 @@
setUpResources();
mExecution = new FakeExecution();
- when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
+ when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
+ .thenReturn(mUdfpsView);
+ when(mLayoutInflater.inflate(R.layout.udfps_enroll_view, null))
+ .thenReturn(mEnrollView); // for showOverlay REASON_ENROLL_ENROLLING
+ when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view, null))
+ .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
+ when(mEnrollView.getContext()).thenReturn(mContext);
final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
@@ -208,7 +226,10 @@
mUdfpsHapticsSimulator,
Optional.of(mHbmProvider),
mKeyguardStateController,
- mKeyguardBypassController);
+ mKeyguardBypassController,
+ mDisplayManager,
+ mHandler,
+ mConfigurationController);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -258,6 +279,75 @@
}
@Test
+ public void onActionMove_dozing_setDeviceEntryIntent() throws RemoteException {
+ // GIVEN the current animation is UdfpsKeyguardViewController and device IS dozing
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN device entry intent is never to true b/c device was dozing on touch
+ verify(mKeyguardBypassController, never()).setUserHasDeviceEntryIntent(true);
+ }
+
+ @Test
+ public void onActionMove_onKeyguard_setDeviceEntryIntent() throws RemoteException {
+ // GIVEN the current animation is UdfpsKeyguardViewController and device isn't dozing
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN device entry intent is set to true
+ verify(mKeyguardBypassController).setUserHasDeviceEntryIntent(true);
+ }
+
+ @Test
+ public void onActionMove_onEnrollment_neverSetDeviceEntryIntent() throws RemoteException {
+ // GIVEN the current animation is UdfpsEnrollViewController
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(
+ mock(UdfpsEnrollViewController.class));
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN device entry intent is never set
+ verify(mKeyguardBypassController, never()).setUserHasDeviceEntryIntent(anyBoolean());
+ }
+
+ @Test
public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
// GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
@@ -324,18 +414,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/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 57c57ec..cc34c30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import org.junit.Before;
@@ -77,6 +78,8 @@
@Mock
private KeyguardViewMediator mKeyguardViewMediator;
@Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
private UdfpsController mUdfpsController;
private UdfpsKeyguardViewController mController;
@@ -111,6 +114,7 @@
mDumpManager,
mKeyguardViewMediator,
mLockscreenShadeTransitionController,
+ mConfigurationController,
mUdfpsController);
}
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..111f3d1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.Mockito;
+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);
+ when(mCommunalView.isAttachedToWindow()).thenReturn(true);
+
+ mController = new CommunalHostViewController(mFakeExecutor, mKeyguardStateController,
+ mStatusBarStateController, mCommunalView);
+ mController.init();
+ mFakeExecutor.runAllReady();
+ }
+
+ @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).
+ Mockito.clearInvocations(mCommunalView);
+ 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/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 1dacc62..ad08780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -33,8 +34,9 @@
import android.app.trust.TrustManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
@@ -65,7 +67,7 @@
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class KeyguardViewMediatorTest extends SysuiTestCase {
private KeyguardViewMediator mViewMediator;
@@ -124,6 +126,7 @@
mUnlockedScreenOffAnimationController,
() -> mNotificationShadeDepthController);
mViewMediator.start();
+ mViewMediator.onSystemReady();
}
@Test
@@ -160,4 +163,27 @@
mViewMediator.onDozeAmountChanged(1f, 1f);
assertFalse(mViewMediator.isAnimatingScreenOff());
}
+
+ @Test
+ public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() {
+ // When showing and provisioned
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ mViewMediator.setShowingLocked(true);
+
+ // and a SIM becomes locked and requires a PIN
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+
+ // and the keyguard goes away
+ mViewMediator.setShowingLocked(false);
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false);
+
+ TestableLooper.get(this).processAllMessages();
+
+ // then make sure it comes back
+ verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null);
+ }
}
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/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index c40977b..109721f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -53,8 +53,8 @@
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.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
@@ -92,7 +92,7 @@
@Mock
private MediaHost mQQSMediaHost;
@Mock
- private FeatureFlags mFeatureFlags;
+ private KeyguardBypassController mBypassController;
@Mock
private FalsingManager mFalsingManager;
@@ -184,8 +184,9 @@
new QSDetailDisplayer(),
mQSMediaHost,
mQQSMediaHost,
+ mBypassController,
mQsComponentFactory,
- mFeatureFlags,
- mFalsingManager);
+ mFalsingManager,
+ mock(DumpManager.class));
}
}
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/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index f208b80..3b78632 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -53,6 +53,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -64,7 +65,6 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
-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;
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..66a006f 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
@@ -27,7 +27,7 @@
import com.android.systemui.plugins.qs.QSTileView
import com.android.systemui.qs.customize.QSCustomizerController
import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -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..b34433c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -23,8 +23,10 @@
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyDialogController
@@ -32,7 +34,6 @@
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.Clock
@@ -49,8 +50,9 @@
import org.mockito.Answers
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.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -92,6 +94,8 @@
@Mock
private lateinit var variableDateViewController: VariableDateViewController
@Mock
+ private lateinit var batteryMeterViewController: BatteryMeterViewController
+ @Mock
private lateinit var clock: Clock
@Mock
private lateinit var variableDateView: VariableDateView
@@ -106,6 +110,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 +126,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,
@@ -132,7 +147,8 @@
privacyDialogController,
qsExpansionPathInterpolator,
featureFlags,
- variableDateViewControllerFactory
+ variableDateViewControllerFactory,
+ batteryMeterViewController
)
}
@@ -152,10 +168,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 +179,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 +190,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 +201,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 +218,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..126b332 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;
@@ -34,8 +37,8 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.util.CarrierConfigTracker;
@@ -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/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4a1411a..a6d044a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -55,12 +55,12 @@
import com.android.internal.logging.InstanceId;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
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/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index facb19f..68df19e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -138,9 +138,12 @@
}
@Test
- public void getSubtitleText_withWifiOn_returnSearchWifi() {
+ public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ List<ScanResult> wifiScanResults = mock(ArrayList.class);
+ doReturn(0).when(wifiScanResults).size();
+ when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(true),
getResourcesString("wifi_empty_list_wifi_on")));
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 94bd959..a1a7e71 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
@@ -2,8 +2,12 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -11,6 +15,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -34,10 +39,13 @@
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.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -170,6 +178,59 @@
verify(mInternetDialogController).launchNetworkSetting();
}
+ @Test
+ public void showProgressBar_wifiDisabled_hideProgressBar() {
+ when(mMockWifiManager.isWifiEnabled()).thenReturn(false);
+
+ mInternetDialog.showProgressBar();
+
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+ verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
+ }
+
+ @Test
+ public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
+ when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
+ List<ScanResult> wifiScanResults = mock(ArrayList.class);
+ when(wifiScanResults.size()).thenReturn(1);
+ when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+
+ mInternetDialog.showProgressBar();
+
+ // Show progress bar
+ assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mHandler).postDelayed(runnableCaptor.capture(),
+ eq(InternetDialog.PROGRESS_DELAY_MS));
+ runnableCaptor.getValue().run();
+
+ // Then hide progress bar
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+ }
+
+ @Test
+ public void showProgressBar_wifiEnabledWithoutWifiScanResults_showProgressBarThenHideSearch() {
+ when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
+ List<ScanResult> wifiScanResults = mock(ArrayList.class);
+ when(wifiScanResults.size()).thenReturn(0);
+ when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+
+ mInternetDialog.showProgressBar();
+
+ // Show progress bar
+ assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mHandler).postDelayed(runnableCaptor.capture(),
+ eq(InternetDialog.PROGRESS_DELAY_MS));
+ runnableCaptor.getValue().run();
+
+ // Then hide searching sub-title only
+ assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+ assertThat(mInternetDialog.mIsSearchingHidden).isTrue();
+ }
+
private class MockInternetDialog extends InternetDialog {
private String mMobileNetworkTitle;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 3a4bc69..670a130 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -26,7 +26,6 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import android.content.Context;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -36,7 +35,6 @@
import android.view.ScrollCaptureResponse;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
@@ -83,7 +81,7 @@
/* taskId */ anyInt(), any(IScrollCaptureResponseListener.class));
// Create client
- ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm);
+ ScrollCaptureClient client = new ScrollCaptureClient(mWm, Runnable::run, mContext);
// Request scroll capture
ListenableFuture<ScrollCaptureResponse> requestFuture =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index d5a2919..be7917a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -33,7 +33,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -125,25 +125,25 @@
public void testOnSystemBarAttributesChanged() {
doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, new InsetsState(), "test");
+ BEHAVIOR_DEFAULT, new InsetsVisibilities(), "test");
}
@Test
public void testOnSystemBarAttributesChangedForSecondaryDisplay() {
doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, new InsetsState(), "test");
+ BEHAVIOR_DEFAULT, new InsetsVisibilities(), "test");
}
private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
waitForIdleSync();
verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance),
eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior),
- eq(requestedState), eq(packageName));
+ eq(requestedVisibilities), eq(packageName));
}
@Test
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..f5ce673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -81,6 +81,7 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -146,6 +147,8 @@
private LockPatternUtils mLockPatternUtils;
@Mock
private IActivityManager mIActivityManager;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
@@ -154,6 +157,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());
@@ -213,7 +219,8 @@
mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
- mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mIActivityManager);
+ mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mIActivityManager,
+ mKeyguardBypassController);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -223,6 +230,10 @@
mController.mRotateTextViewController = mRotateTextViewController;
mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
clearInvocations(mIBatteryStats);
+
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallbackCaptor.capture());
+ mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
}
@Test
@@ -500,6 +511,7 @@
createController();
String message = mContext.getString(R.string.keyguard_retry);
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
mController.setVisible(true);
mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
@@ -529,7 +541,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 +584,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/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index 85ec3fa..f2671b76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -22,7 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 116f807..a2bb0af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -41,7 +41,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.android.systemui.util.concurrency.FakeExecution
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 1be14b6..8a32ce6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -64,7 +64,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 9a5482c..39d794d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -67,7 +67,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
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/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index cea49b7..0854b93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -47,11 +47,11 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
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..07ebaea 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;
@@ -45,11 +46,11 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -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..4e76b16 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
@@ -52,11 +52,8 @@
import com.android.systemui.R;
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 +94,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 +122,6 @@
new NotificationSection[]{
mNotificationSection
});
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
// Interact with real instance of AmbientState.
mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController);
@@ -146,7 +138,6 @@
mGroupMembershipManger,
mGroupExpansionManager,
mAmbientState,
- mFeatureFlags,
mUnlockedScreenOffAnimationController);
mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
@@ -156,7 +147,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 +220,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 +294,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..55c69f7 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
@@ -37,12 +37,16 @@
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.CommandQueue;
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/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 5bf1bb3..7a0b366 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -38,7 +38,7 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
new file mode 100644
index 0000000..9cc762c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
+ @Mock
+ private KeyguardStatusBarView mKeyguardStatusBarView;
+ @Mock
+ private ViewGroup mViewGroup;
+ @Mock
+ private CarrierTextController mCarrierTextController;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private SystemStatusAnimationScheduler mAnimationScheduler;
+ @Mock
+ private BatteryController mBatteryController;
+ @Mock
+ private UserInfoController mUserInfoController;
+ @Mock
+ private StatusBarIconController mStatusBarIconController;
+ @Mock
+ private FeatureFlags mFeatureFlags;
+ @Mock
+ private BatteryMeterViewController mBatteryMeterViewController;
+
+ private KeyguardStatusBarViewController mController;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mKeyguardStatusBarView.getResources()).thenReturn(mContext.getResources());
+ when(mKeyguardStatusBarView.findViewById(R.id.statusIcons)).thenReturn(mViewGroup);
+ when(mViewGroup.getContext()).thenReturn(mContext);
+
+ mController = new KeyguardStatusBarViewController(
+ mKeyguardStatusBarView,
+ mCarrierTextController,
+ mConfigurationController,
+ mAnimationScheduler,
+ mBatteryController,
+ mUserInfoController,
+ mStatusBarIconController,
+ new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
+ mBatteryMeterViewController
+ );
+ }
+
+ @Test
+ public void onViewAttached_callbacksRegistered() {
+ mController.onViewAttached();
+
+ verify(mConfigurationController).addCallback(any());
+ verify(mAnimationScheduler).addCallback(any());
+ verify(mUserInfoController).addCallback(any());
+ verify(mStatusBarIconController).addIconGroup(any());
+ }
+
+ @Test
+ public void onViewDetached_callbacksUnregistered() {
+ // Set everything up first.
+ mController.onViewAttached();
+
+ mController.onViewDetached();
+
+ verify(mConfigurationController).removeCallback(any());
+ verify(mAnimationScheduler).removeCallback(any());
+ verify(mUserInfoController).removeCallback(any());
+ verify(mStatusBarIconController).removeIconGroup(any());
+ }
+
+ @Test
+ public void setBatteryListening_true_callbackAdded() {
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_false_callbackRemoved() {
+ // First set to true so that we know setting to false is a change in state.
+ mController.setBatteryListening(true);
+
+ mController.setBatteryListening(false);
+
+ verify(mBatteryController).removeCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_trueThenTrue_callbackAddedOnce() {
+ mController.setBatteryListening(true);
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index c3adee9..74f08ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -102,7 +102,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
assertTrue(mLightsOutNotifController.areLightsOut());
}
@@ -115,7 +115,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
assertFalse(mLightsOutNotifController.areLightsOut());
}
@@ -146,7 +146,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we should show dot
@@ -166,7 +166,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we shouldn't show the dot
@@ -186,7 +186,7 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- null /* requestedState */,
+ null /* requestedVisibilities */,
null /* packageName */);
// THEN we shouldn't show the dot
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..8f6a297 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,9 +88,17 @@
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.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.idle.IdleHostViewController;
+import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -99,7 +107,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 +115,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 +144,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.lang.ref.WeakReference;
import java.util.List;
@SmallTest
@@ -240,6 +247,12 @@
@Mock
private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
@Mock
+ private IdleViewComponent.Factory mIdleViewComponentFactory;
+ @Mock
+ private IdleViewComponent mIdleViewComponent;
+ @Mock
+ private IdleHostViewController mIdleHostViewController;
+ @Mock
private QSDetailDisplayer mQSDetailDisplayer;
@Mock
private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
@@ -248,6 +261,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 +291,6 @@
@Mock
private MediaDataManager mMediaDataManager;
@Mock
- private FeatureFlags mFeatureFlags;
- @Mock
private AmbientState mAmbientState;
@Mock
private UserManager mUserManager;
@@ -300,9 +323,9 @@
@Mock
private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock
- private RemoteInputController mRemoteInputController;
- @Mock
private RecordingController mRecordingController;
+ @Mock
+ private ControlsComponent mControlsComponent;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -339,6 +362,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);
@@ -375,16 +399,17 @@
mKeyguardBypassController,
mDozeParameters,
mUnlockedScreenOffAnimationController);
+ mConfigurationController = new ConfigurationControllerImpl(mContext);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
coordinator,
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
+ mConfigurationController,
mStatusBarStateController,
mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
- mConfigurationController = new ConfigurationControllerImpl(mContext);
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -395,12 +420,19 @@
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ when(mCommunalViewComponentFactory.build(any()))
+ .thenReturn(mCommunalViewComponent);
+ when(mCommunalViewComponent.getCommunalHostViewController())
+ .thenReturn(mCommunalHostViewController);
+ when(mIdleViewComponentFactory.build(any()))
+ .thenReturn(mIdleViewComponent);
+ when(mIdleViewComponent.getIdleHostViewController())
+ .thenReturn(mIdleHostViewController);
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 +446,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 +455,8 @@
mKeyguardQsUserSwitchComponentFactory,
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
+ mCommunalViewComponentFactory,
+ mIdleViewComponentFactory,
mLockscreenShadeTransitionController,
mQSDetailDisplayer,
mGroupManager,
@@ -434,7 +468,6 @@
mNotificationShadeDepthController,
mAmbientState,
mLockIconViewController,
- mFeatureFlags,
mKeyguardMediaController,
mPrivacyDotViewController,
mTapAgainViewController,
@@ -447,7 +480,8 @@
mSecureSettings,
mSplitShadeHeaderController,
mUnlockedScreenOffAnimationController,
- mNotificationRemoteInputManager);
+ mNotificationRemoteInputManager,
+ mControlsComponent);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
@@ -560,7 +594,7 @@
@Test
public void testAllChildrenOfNotificationContainer_haveIds() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationContainerParent.removeAllViews();
mNotificationContainerParent.addView(newViewWithId(1));
mNotificationContainerParent.addView(newViewWithId(View.NO_ID));
@@ -573,7 +607,7 @@
@Test
public void testSinglePaneShadeLayout_isAlignedToParent() {
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ enableSplitShade(/* enabled= */ false);
mNotificationPanelViewController.updateResources();
@@ -586,7 +620,7 @@
@Test
public void testKeyguardStatusViewInSplitShade_changesConstraintsDependingOnNotifications() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
mNotificationPanelViewController.updateResources();
@@ -633,7 +667,7 @@
@Test
public void testSplitShadeLayout_isAlignedToGuideline() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.updateResources();
@@ -645,7 +679,7 @@
@Test
public void testSinglePaneShadeLayout_childrenHaveConstantWidth() {
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ enableSplitShade(/* enabled= */ false);
mNotificationPanelViewController.updateResources();
@@ -657,7 +691,7 @@
@Test
public void testSplitShadeLayout_childrenHaveZeroWidth() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.updateResources();
@@ -669,7 +703,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 +737,7 @@
@Test
public void testCanCollapsePanelOnTouch_falseInDualPaneShade() {
mStatusBarStateController.setState(SHADE);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.setQsExpanded(true);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
@@ -773,7 +807,7 @@
@Test
public void testSwitchesToCorrectClockInSplitShade() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
triggerPositionClockAndNotifications();
@@ -788,7 +822,7 @@
@Test
public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
// one notification + media player visible
@@ -803,6 +837,35 @@
verify(mKeyguardStatusViewController, never()).displayClock(LARGE);
}
+ @Test
+ public void testCommunalhostViewControllerInit() {
+ clearInvocations(mCommunalHostViewController);
+ givenViewAttached();
+ verify(mCommunalHostViewController).init();
+ }
+
+ @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 +884,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 +907,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/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 2685b76..30fc13b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -83,7 +83,6 @@
private ScrimView mScrimBehind;
private ScrimView mNotificationsScrim;
private ScrimView mScrimInFront;
- private ScrimView mScrimForBubble;
private ScrimState mScrimState;
private float mScrimBehindAlpha;
private GradientColors mScrimInFrontColor;
@@ -167,7 +166,6 @@
endAnimation(mNotificationsScrim);
endAnimation(mScrimBehind);
endAnimation(mScrimInFront);
- endAnimation(mScrimForBubble);
assertEquals("Animators did not finish",
mAnimatorListener.getNumStarts(), mAnimatorListener.getNumEnds());
@@ -190,7 +188,6 @@
mScrimBehind = spy(new ScrimView(getContext()));
mScrimInFront = new ScrimView(getContext());
- mScrimForBubble = new ScrimView(getContext());
mNotificationsScrim = new ScrimView(getContext());
mAlwaysOnEnabled = true;
mLooper = TestableLooper.get(this);
@@ -226,8 +223,7 @@
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mUnlockedScreenOffAnimationController);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
- mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront,
- mScrimForBubble);
+ mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
mScrimController.setHasBackdrop(false);
@@ -257,8 +253,8 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false));
+ mScrimBehind, true
+ ));
}
@Test
@@ -274,8 +270,7 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -293,8 +288,7 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -309,8 +303,7 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
@@ -329,8 +322,7 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -369,8 +361,7 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -389,8 +380,7 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -510,8 +500,7 @@
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
// ... and when ambient goes dark, front scrim should be semi-transparent
@@ -549,8 +538,7 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, false,
- mNotificationsScrim, false,
- mScrimForBubble, false
+ mNotificationsScrim, false
));
}
@@ -570,8 +558,7 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, true,
- mNotificationsScrim, false,
- mScrimForBubble, false
+ mNotificationsScrim, false
));
}
@@ -627,8 +614,7 @@
mScrimBehind, TRANSPARENT));
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, false,
- mScrimForBubble, false
+ mScrimBehind, false
));
}
@@ -645,8 +631,7 @@
assertScrimTinted(Map.of(
mNotificationsScrim, false,
mScrimInFront, false,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
// Back scrim should be visible after start dragging
@@ -657,27 +642,6 @@
mScrimBehind, SEMI_TRANSPARENT));
}
- @Test
- public void transitionToBubbleExpanded() {
- mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
- finishAnimationsImmediately();
-
- assertScrimTinted(Map.of(
- mScrimInFront, false,
- mScrimBehind, false,
- mScrimForBubble, true
- ));
-
- // Front scrim should be transparent
- assertEquals(ScrimController.TRANSPARENT,
- mScrimInFront.getViewAlpha(), 0.0f);
- // Back scrim should be visible
- assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
- mScrimBehind.getViewAlpha(), 0.0f);
- // Bubble scrim should be visible
- assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA,
- mScrimForBubble.getViewAlpha(), 0.0f);
- }
@Test
public void scrimStateCallback() {
@@ -787,8 +751,7 @@
// Immediately tinted black after the transition starts
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, true
+ mScrimBehind, true
));
finishAnimationsImmediately();
@@ -796,14 +759,12 @@
// All scrims should be transparent at the end of fade transition.
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, TRANSPARENT,
- mScrimForBubble, TRANSPARENT));
+ mScrimBehind, TRANSPARENT));
// Make sure at the very end of the animation, we're reset to transparent
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, true,
- mScrimForBubble, false
+ mScrimBehind, true
));
}
@@ -821,8 +782,7 @@
+ mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0);
assertScrimTinted(Map.of(
mScrimInFront, true,
- mScrimBehind, true,
- mScrimForBubble, true
+ mScrimBehind, true
));
Assert.assertSame("Scrim should be visible during transition.",
mScrimVisibility, OPAQUE);
@@ -1075,8 +1035,6 @@
mScrimInFront.getDefaultFocusHighlightEnabled());
Assert.assertFalse("Scrim shouldn't have focus highlight",
mScrimBehind.getDefaultFocusHighlightEnabled());
- Assert.assertFalse("Scrim shouldn't have focus highlight",
- mScrimForBubble.getDefaultFocusHighlightEnabled());
}
@Test
@@ -1086,7 +1044,7 @@
HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
- ScrimState.BUBBLE_EXPANDED, ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
+ ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
@@ -1239,21 +1197,16 @@
return "behind";
} else if (scrim == mNotificationsScrim) {
return "notifications";
- } else if (scrim == mScrimForBubble) {
- return "bubble";
}
return "unknown_scrim";
}
/**
- * If {@link #mScrimForBubble} or {@link #mNotificationsScrim} is not passed in the map
+ * If {@link #mNotificationsScrim} is not passed in the map
* we assume it must be transparent
*/
private void assertScrimAlpha(Map<ScrimView, Integer> scrimToAlpha) {
// Check single scrim visibility.
- if (!scrimToAlpha.containsKey(mScrimForBubble)) {
- assertScrimAlpha(mScrimForBubble, TRANSPARENT);
- }
if (!scrimToAlpha.containsKey(mNotificationsScrim)) {
assertScrimAlpha(mNotificationsScrim, TRANSPARENT);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
new file mode 100644
index 0000000..52538c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.StatusBarManager;
+import android.os.PowerManager;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase {
+ @Mock private StatusBar mStatusBar;
+ @Mock private ShadeController mShadeController;
+ @Mock private CommandQueue mCommandQueue;
+ @Mock private NotificationPanelViewController mNotificationPanelViewController;
+ @Mock private LegacySplitScreen mLegacySplitScreen;
+ @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private HeadsUpManagerPhone mHeadsUpManager;
+ @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
+ @Mock private DeviceProvisionedController mDeviceProvisionedController;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private AssistManager mAssistManager;
+ @Mock private DozeServiceHost mDozeServiceHost;
+ @Mock private StatusBarStateControllerImpl mStatusBarStateController;
+ @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
+ @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ @Mock private PowerManager mPowerManager;
+ @Mock private VibratorHelper mVibratorHelper;
+ @Mock private Vibrator mVibrator;
+ @Mock private LightBarController mLightBarController;
+
+ StatusBarCommandQueueCallbacks mSbcqCallbacks;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mSbcqCallbacks = new StatusBarCommandQueueCallbacks(
+ mStatusBar,
+ mContext,
+ mContext.getResources(),
+ mShadeController,
+ mCommandQueue,
+ mNotificationPanelViewController,
+ Optional.of(mLegacySplitScreen),
+ mRemoteInputQuickSettingsDisabler,
+ mMetricsLogger,
+ mKeyguardUpdateMonitor,
+ mKeyguardStateController,
+ mHeadsUpManager,
+ mWakefulnessLifecycle,
+ mDeviceProvisionedController,
+ mStatusBarKeyguardViewManager,
+ mAssistManager,
+ mDozeServiceHost,
+ mStatusBarStateController,
+ mNotificationShadeWindowView,
+ mNotificationStackScrollLayoutController,
+ mPowerManager,
+ mVibratorHelper,
+ Optional.of(mVibrator),
+ mLightBarController,
+ DEFAULT_DISPLAY);
+
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+ when(mRemoteInputQuickSettingsDisabler.adjustDisableFlags(anyInt()))
+ .thenAnswer((Answer<Integer>) invocation -> invocation.getArgument(0));
+ }
+
+ @Test
+ public void testDisableNotificationShade() {
+ when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mCommandQueue.panelsEnabled()).thenReturn(false);
+ mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
+
+ verify(mStatusBar).updateQsExpansionEnabled();
+ verify(mShadeController).animateCollapsePanels();
+
+ // Trying to open it does nothing.
+ mSbcqCallbacks.animateExpandNotificationsPanel();
+ verify(mNotificationPanelViewController, never()).expandWithoutQs();
+ mSbcqCallbacks.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelViewController, never()).expand(anyBoolean());
+ }
+
+ @Test
+ public void testEnableNotificationShade() {
+ when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE2_NOTIFICATION_SHADE);
+ when(mCommandQueue.panelsEnabled()).thenReturn(true);
+ mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NONE, false);
+ verify(mStatusBar).updateQsExpansionEnabled();
+ verify(mShadeController, never()).animateCollapsePanels();
+
+ // Can now be opened.
+ mSbcqCallbacks.animateExpandNotificationsPanel();
+ verify(mNotificationPanelViewController).expandWithoutQs();
+ mSbcqCallbacks.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelViewController).expandWithQs();
+ }
+
+ @Test
+ public void testSuppressAmbientDisplay_suppress() {
+ mSbcqCallbacks.suppressAmbientDisplay(true);
+ verify(mDozeServiceHost).setDozeSuppressed(true);
+ }
+
+ @Test
+ public void testSuppressAmbientDisplay_unsuppress() {
+ mSbcqCallbacks.suppressAmbientDisplay(false);
+ verify(mDozeServiceHost).setDozeSuppressed(false);
+ }
+
+
+}
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/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index e3263d4..0f1c40b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -30,8 +30,8 @@
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
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..72a3d66 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
@@ -53,15 +53,14 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationClickNotifier;
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..c06a9ae 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
@@ -18,7 +18,6 @@
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.view.Display.DEFAULT_DISPLAY;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -40,7 +39,7 @@
import android.app.IWallpaperManager;
import android.app.Notification;
-import android.app.StatusBarManager;
+import android.app.WallpaperManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -78,28 +77,25 @@
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationListener;
@@ -110,15 +106,11 @@
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;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -143,13 +135,14 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-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;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -180,7 +173,6 @@
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
- @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private KeyguardIndicationController mKeyguardIndicationController;
@@ -201,12 +193,10 @@
@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;
@Mock private StatusBarNotificationPresenter mNotificationPresenter;
- @Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationFilter mNotificationFilter;
@Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@@ -217,7 +207,6 @@
@Mock private NotificationGutsManager mNotificationGutsManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
@Mock private NavigationBarController mNavigationBarController;
- @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
@Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private ColorExtractor.GradientColors mGradientColors;
@@ -229,7 +218,6 @@
@Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
@Mock private UserSwitcherController mUserSwitcherController;
@Mock private NetworkController mNetworkController;
- @Mock private VibratorHelper mVibratorHelper;
@Mock private BubblesManager mBubblesManager;
@Mock private Bubbles mBubbles;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -240,7 +228,6 @@
@Mock private LockscreenWallpaper mLockscreenWallpaper;
@Mock private DozeServiceHost mDozeServiceHost;
@Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
- @Mock private KeyguardLiftController mKeyguardLiftController;
@Mock private VolumeComponent mVolumeComponent;
@Mock private CommandQueue mCommandQueue;
@Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
@@ -251,12 +238,10 @@
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
- @Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
- @Mock private DarkIconDispatcher mDarkIconDispatcher;
@Mock private PluginDependencyProvider mPluginDependencyProvider;
@Mock private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock private ExtensionController mExtensionController;
@@ -265,13 +250,16 @@
@Mock private DemoModeController mDemoModeController;
@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;
+ @Mock private WallpaperManager mWallpaperManager;
+ @Mock private IWallpaperManager mIWallpaperManager;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock private StartingSurface mStartingSurface;
@@ -331,10 +319,8 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
WakefulnessLifecycle wakefulnessLifecycle =
- new WakefulnessLifecycle(mContext, mWallpaperManager);
+ new WakefulnessLifecycle(mContext, mIWallpaperManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
wakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -361,7 +347,6 @@
mLightBarController,
mAutoHideController,
mKeyguardUpdateMonitor,
- mStatusBarSignalPolicy,
mPulseExpansionHandler,
mNotificationWakeUpCoordinator,
mKeyguardBypassController,
@@ -372,11 +357,6 @@
new FalsingManagerFake(),
new FalsingCollectorFake(),
mBroadcastDispatcher,
- new RemoteInputQuickSettingsDisabler(
- mContext,
- configurationController,
- mCommandQueue
- ),
mNotificationGutsManager,
notificationLogger,
mNotificationInterruptStateProvider,
@@ -395,19 +375,16 @@
new ScreenLifecycle(),
wakefulnessLifecycle,
mStatusBarStateController,
- mVibratorHelper,
Optional.of(mBubblesManager),
Optional.of(mBubbles),
mVisualStabilityManager,
mDeviceProvisionedController,
mNavigationBarController,
- mAccessibilityFloatingMenuController,
() -> mAssistManager,
configurationController,
mNotificationShadeWindowController,
mDozeParameters,
mScrimController,
- mKeyguardLiftController,
mLockscreenWallpaperLazy,
mBiometricUnlockControllerLazy,
mDozeServiceHost,
@@ -432,19 +409,21 @@
mUserInfoControllerImpl,
mPhoneStatusBarPolicy,
mKeyguardIndicationController,
- mDismissCallbackRegistry,
mDemoModeController,
mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager,
mNotificationIconAreaController,
mBrightnessSliderFactory,
- mWiredChargingRippleController,
+ mUnfoldTransitionConfig,
+ mUnfoldLightRevealOverlayAnimationLazy,
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
+ mIconController,
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
+ mWallpaperManager,
mUnlockedScreenOffAnimationController,
Optional.of(mStartingSurface));
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
@@ -750,31 +729,6 @@
}
@Test
- public void testDisableExpandStatusBar() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- mStatusBar.setUserSetupForTest(true);
- when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-
- when(mCommandQueue.panelsEnabled()).thenReturn(false);
- mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
- verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(false);
- mStatusBar.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController, never()).expand(anyBoolean());
- mStatusBar.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController, never()).expand(anyBoolean());
-
- when(mCommandQueue.panelsEnabled()).thenReturn(true);
- mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NONE, false);
- verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(true);
- mStatusBar.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController).expandWithoutQs();
- mStatusBar.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController).expandWithQs();
- }
-
- @Test
public void testDump_DoesNotCrash() {
mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null);
}
@@ -901,18 +855,6 @@
}
@Test
- public void testSuppressAmbientDisplay_suppress() {
- mStatusBar.suppressAmbientDisplay(true);
- verify(mDozeServiceHost).setDozeSuppressed(true);
- }
-
- @Test
- public void testSuppressAmbientDisplay_unsuppress() {
- mStatusBar.suppressAmbientDisplay(false);
- verify(mDozeServiceHost).setDozeSuppressed(false);
- }
-
- @Test
public void testUpdateResources_updatesBouncer() {
mStatusBar.updateResources();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index d36cb0b..31fa04d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -34,7 +34,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -223,7 +223,6 @@
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
-
@Test
fun onEntryRemoved_notifKeyDoesNotMatchOngoingCallNotif_listenerNotNotified() {
notifCollectionListener.onEntryAdded(createOngoingCallNotifEntry())
@@ -349,7 +348,7 @@
// Update the process to visible.
uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_VISIBLE, 0, 0)
mainExecutor.advanceClockToLast()
- mainExecutor.runAllReady();
+ mainExecutor.runAllReady()
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
@@ -370,7 +369,7 @@
// Update the process to invisible.
uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_INVISIBLE, 0, 0)
mainExecutor.advanceClockToLast()
- mainExecutor.runAllReady();
+ mainExecutor.runAllReady()
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
new file mode 100644
index 0000000..30717f4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+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;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
+
+ private static final String[] DEFAULT_SETTINGS = new String[]{
+ "0:0",
+ "1:2"
+ };
+
+ private final FakeSettings mFakeSettings = new FakeSettings();
+ private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
+ @Mock DeviceStateManager mDeviceStateManager;
+ RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
+ DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+
+ ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(
+ DeviceStateManager.DeviceStateCallback.class);
+
+ mDeviceStateRotationLockSettingController = new DeviceStateRotationLockSettingController(
+ mFakeSettings,
+ mFakeRotationPolicy,
+ mDeviceStateManager,
+ mFakeExecutor,
+ DEFAULT_SETTINGS
+ );
+
+ mDeviceStateRotationLockSettingController.setListening(true);
+ verify(mDeviceStateManager).registerCallback(any(),
+ deviceStateCallbackArgumentCaptor.capture());
+ mDeviceStateCallback = deviceStateCallbackArgumentCaptor.getValue();
+ }
+
+ @Test
+ public void whenSavedSettingsEmpty_defaultsLoadedAndSaved() {
+ mFakeSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK, "",
+ UserHandle.USER_CURRENT);
+
+ mDeviceStateRotationLockSettingController.initialize();
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:0:1:2");
+ }
+
+ @Test
+ public void whenNoSavedValueForDeviceState_assumeIgnored() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:2:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ // Settings only exist for state 0 and 1
+ mDeviceStateCallback.onStateChanged(2);
+
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+ }
+
+ @Test
+ public void whenDeviceStateSwitched_loadCorrectSetting() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:2:1:1",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+ }
+
+ @Test
+ public void whenUserChangesSetting_saveSettingForCurrentState() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:1:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+ mDeviceStateRotationLockSettingController
+ .onRotationLockStateChanged(/* rotationLocked= */false,
+ /* affordanceVisible= */ true);
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:2:1:2");
+ }
+
+
+ @Test
+ public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:0:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+ }
+
+ @Test
+ public void whenDeviceStateSwitchedToIgnoredState_newSettingsSaveForPreviousState() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:0:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateRotationLockSettingController
+ .onRotationLockStateChanged(/* rotationLocked= */true,
+ /* affordanceVisible= */ true);
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:0:1:1");
+ }
+
+ private static class FakeRotationPolicy implements RotationPolicyWrapper {
+
+ private boolean mRotationLock;
+
+ @Override
+ public void setRotationLock(boolean enabled) {
+ mRotationLock = enabled;
+ }
+
+ @Override
+ public void setRotationLockAtAngle(boolean enabled, int rotation) {
+ mRotationLock = enabled;
+ }
+
+ @Override
+ public int getRotationLockOrientation() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isRotationLockToggleVisible() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isRotationLocked() {
+ return mRotationLock;
+ }
+
+ @Override
+ public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
+ int userHandle) {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public void unregisterRotationPolicyListener(
+ RotationPolicy.RotationPolicyListener listener) {
+ throw new AssertionError("Not implemented");
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index f2de26c..21c4a17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
new file mode 100644
index 0000000..0581264
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+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;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class RotationLockControllerImplTest extends SysuiTestCase {
+
+ private static final String[] DEFAULT_SETTINGS = new String[]{
+ "0:0",
+ "1:2"
+ };
+
+ @Mock RotationPolicyWrapper mRotationPolicyWrapper;
+ @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+
+ private TestableResources mResources;
+ private ArgumentCaptor<RotationPolicy.RotationPolicyListener>
+ mRotationPolicyListenerCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+ mResources = mContext.getOrCreateTestableResources();
+
+ mRotationPolicyListenerCaptor = ArgumentCaptor.forClass(
+ RotationPolicy.RotationPolicyListener.class);
+ }
+
+ @Test
+ public void whenFlagOff_doesntInteractWithDeviceStateRotationController() {
+ createRotationLockController(new String[0]);
+
+ verifyZeroInteractions(mDeviceStateRotationLockSettingController);
+ }
+
+ @Test
+ public void whenFlagOn_setListeningSetsListeningOnDeviceStateRotationController() {
+ createRotationLockController();
+
+ verify(mDeviceStateRotationLockSettingController).setListening(/* listening= */ true);
+ }
+
+ @Test
+ public void whenFlagOn_initializesDeviceStateRotationController() {
+ createRotationLockController();
+
+ verify(mDeviceStateRotationLockSettingController).initialize();
+ }
+
+ @Test
+ public void whenFlagOn_dviceStateRotationControllerAddedToCallbacks() {
+ createRotationLockController();
+ captureRotationPolicyListener().onChange();
+
+ verify(mDeviceStateRotationLockSettingController)
+ .onRotationLockStateChanged(anyBoolean(), anyBoolean());
+ }
+
+ private RotationPolicy.RotationPolicyListener captureRotationPolicyListener() {
+ verify(mRotationPolicyWrapper)
+ .registerRotationPolicyListener(mRotationPolicyListenerCaptor.capture(), anyInt());
+ return mRotationPolicyListenerCaptor.getValue();
+ }
+
+ private void createRotationLockController() {
+ createRotationLockController(DEFAULT_SETTINGS);
+ }
+ private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
+ new RotationLockControllerImpl(
+ mRotationPolicyWrapper,
+ mDeviceStateRotationLockSettingController,
+ deviceStateRotationLockDefaults
+ );
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 07d3fc2..f6a54936 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -52,9 +52,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 5efe05f..84e6df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -60,9 +60,9 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
index 8f07545..cc2afe2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
@@ -60,6 +60,25 @@
}
@Test
+ public void testPrimaryBelowDoesNotInvokeSecondary() {
+ TestableListener listener = new TestableListener();
+
+ mProximitySensor.register(listener);
+ assertTrue(mProximitySensor.isRegistered());
+ assertFalse(mThresholdSensorPrimary.isPaused());
+ assertTrue(mThresholdSensorSecondary.isPaused());
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+
+ // Trigger primary sensor. Our secondary sensor is not registered.
+ mThresholdSensorPrimary.triggerEvent(false, 0);
+ assertFalse(mThresholdSensorPrimary.isPaused());
+ assertTrue(mThresholdSensorSecondary.isPaused());
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+ }
+
+ @Test
public void testSingleListener() {
TestableListener listener = new TestableListener();
@@ -256,40 +275,6 @@
}
@Test
- public void testPrimaryCancelsSecondary() {
- TestableListener listener = new TestableListener();
-
- mProximitySensor.register(listener);
- assertFalse(mThresholdSensorPrimary.isPaused());
- assertTrue(mThresholdSensorSecondary.isPaused());
- assertNull(listener.mLastEvent);
- assertEquals(0, listener.mCallCount);
-
- mThresholdSensorPrimary.triggerEvent(true, 0);
- assertNull(listener.mLastEvent);
- assertEquals(0, listener.mCallCount);
- mThresholdSensorSecondary.triggerEvent(true, 0);
- assertTrue(listener.mLastEvent.getBelow());
- assertEquals(1, listener.mCallCount);
-
- // When the primary reports false, the secondary is no longer needed. We get an immediate
- // report.
- mThresholdSensorPrimary.triggerEvent(false, 1);
- assertFalse(listener.mLastEvent.getBelow());
- assertEquals(2, listener.mCallCount);
-
- // The secondary is now ignored. No more work is scheduled.
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runNextReady();
- mThresholdSensorSecondary.triggerEvent(true, 0);
- assertFalse(listener.mLastEvent.getBelow());
- assertEquals(2, listener.mCallCount);
- assertEquals(0, mFakeExecutor.numPending());
-
- mProximitySensor.unregister(listener);
- }
-
- @Test
public void testSecondaryCancelsSecondary() {
TestableListener listener = new TestableListener();
ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() {
@@ -342,7 +327,7 @@
// The secondary sensor should now remain resumed indefinitely.
assertFalse(mThresholdSensorSecondary.isPaused());
- mThresholdSensorPrimary.triggerEvent(false, 1);
+ mThresholdSensorSecondary.triggerEvent(false, 1);
assertFalse(listener.mLastEvent.getBelow());
assertEquals(2, listener.mCallCount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 6976422..7bb2674 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -31,6 +31,7 @@
private final Map<SettingsKey, String> mValues = new HashMap<>();
private final Map<SettingsKey, List<ContentObserver>> mContentObservers =
new HashMap<>();
+ private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
public static final Uri CONTENT_URI = Uri.parse("content://settings/fake");
@@ -55,9 +56,15 @@
@Override
public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
ContentObserver settingsObserver, int userHandle) {
- SettingsKey key = new SettingsKey(userHandle, uri.toString());
- mContentObservers.putIfAbsent(key, new ArrayList<>());
- List<ContentObserver> observers = mContentObservers.get(key);
+ List<ContentObserver> observers;
+ if (userHandle == UserHandle.USER_ALL) {
+ mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>());
+ observers = mContentObserversAllUsers.get(uri.toString());
+ } else {
+ SettingsKey key = new SettingsKey(userHandle, uri.toString());
+ mContentObservers.putIfAbsent(key, new ArrayList<>());
+ observers = mContentObservers.get(key);
+ }
observers.add(settingsObserver);
}
@@ -67,6 +74,10 @@
List<ContentObserver> observers = mContentObservers.get(key);
observers.remove(settingsObserver);
}
+ for (String key : mContentObserversAllUsers.keySet()) {
+ List<ContentObserver> observers = mContentObserversAllUsers.get(key);
+ observers.remove(settingsObserver);
+ }
}
@Override
@@ -114,6 +125,10 @@
for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) {
observer.dispatchChange(false, List.of(uri), userHandle);
}
+ for (ContentObserver observer :
+ mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) {
+ observer.dispatchChange(false, List.of(uri), userHandle);
+ }
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index 0d560f2..34cae58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.verify;
import android.database.ContentObserver;
+import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -89,6 +90,16 @@
}
@Test
+ public void testRegisterContentObserverAllUsers() {
+ mFakeSettings.registerContentObserverForUser(
+ mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+
+ mFakeSettings.putString("cat", "hat");
+
+ verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt());
+ }
+
+ @Test
public void testUnregisterContentObserver() {
mFakeSettings.registerContentObserver("cat", mContentObserver);
mFakeSettings.unregisterContentObserver(mContentObserver);
@@ -98,4 +109,16 @@
verify(mContentObserver, never()).dispatchChange(
anyBoolean(), any(Collection.class), anyInt());
}
+
+ @Test
+ public void testUnregisterContentObserverAllUsers() {
+ mFakeSettings.registerContentObserverForUser(
+ mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+ mFakeSettings.unregisterContentObserver(mContentObserver);
+
+ mFakeSettings.putString("cat", "hat");
+
+ verify(mContentObserver, never()).dispatchChange(
+ anyBoolean(), any(Collection.class), anyInt());
+ }
}
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/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index a0b93ad..9f755f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -76,11 +76,11 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.RankingBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index b0dd73a..a3bbb26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -64,10 +64,10 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml
index b5a8831..5ffdcb1 100644
--- a/packages/VpnDialogs/res/values-gu/strings.xml
+++ b/packages/VpnDialogs/res/values-gu/strings.xml
@@ -29,7 +29,7 @@
<string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g>ને હંમેશાં જોડાયેલ રહેવા માટે સેટ કરેલ છે, પરંતુ તે હાલમાં કનેક્ટ કરી શકાતું નથી. તમારો ફોન જ્યાં સુધી <xliff:g id="VPN_APP_1">%1$s</xliff:g> સાથે ફરીથી કનેક્ટ ન થાય ત્યાં સુધી તે સાર્વજનિક નેટવર્કનો ઉપયોગ કરશે."</string>
<string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g>ને હંમેશાં જોડાયેલ રહેવા માટે સેટ કરેલ છે, પરંતુ તે હાલમાં કનેક્ટ કરી શકાતું નથી. VPN ફરીથી કનેક્ટ ન થઈ શકે ત્યાં સુધી તમારી પાસે કોઈ કનેક્શન હશે નહીં."</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
- <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN સેટિંગ્સ બદલો"</string>
+ <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN સેટિંગ બદલો"</string>
<string name="configure" msgid="4905518375574791375">"ગોઠવો"</string>
<string name="disconnect" msgid="971412338304200056">"ડિસ્કનેક્ટ કરો"</string>
<string name="open_app" msgid="3717639178595958667">"ઍપ ખોલો"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index eec875a..b88366b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1704,6 +1704,10 @@
* @param displayId The logical display id.
*/
private void ensureWindowsAvailableTimedLocked(int displayId) {
+ if (displayId == Display.INVALID_DISPLAY) {
+ return;
+ }
+
if (mA11yWindowManager.getWindowListLocked(displayId) != null) {
return;
}
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/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 8aacafb..19601b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -189,10 +189,10 @@
if (animationCallback.mCurrentMode == targetMode) {
animationCallback.restoreToCurrentMagnificationMode();
return;
+ } else {
+ Slog.w(TAG, "discard duplicate request");
+ return;
}
- Slog.w(TAG, "request during transition, abandon current:"
- + animationCallback.mTargetMode);
- animationCallback.setExpiredAndRemoveFromListLocked();
}
if (magnificationCenter == null) {
@@ -464,7 +464,9 @@
private final TransitionCallBack mTransitionCallBack;
private boolean mExpired = false;
private final int mDisplayId;
+ // The mode the in-progress animation is going to.
private final int mTargetMode;
+ // The mode the in-progress animation is going from.
private final int mCurrentMode;
private final float mCurrentScale;
private final PointF mCurrentCenter = new PointF();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 5aec6aa..a56b1db 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3285,6 +3285,57 @@
}
}
+ private void applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId,
+ boolean updateFrameworkRes) {
+ for (int i = 0, N = mProviders.size(); i < N; i++) {
+ Provider provider = mProviders.get(i);
+ if (provider.getUserId() != userId) {
+ continue;
+ }
+
+ final String packageName = provider.id.componentName.getPackageName();
+ if (!updateFrameworkRes && !packageNames.contains(packageName)) {
+ continue;
+ }
+
+ ApplicationInfo newAppInfo = null;
+ try {
+ newAppInfo = mPackageManager.getApplicationInfo(packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES, userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to retrieve app info for " + packageName
+ + " userId=" + userId, e);
+ }
+ if (newAppInfo == null) {
+ continue;
+ }
+ ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo;
+ if (!newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
+ // Overlay paths are generated against a particular version of an application.
+ // The overlays paths of a newly upgraded application are incompatible with the
+ // old version of the application.
+ continue;
+ }
+
+ // Isolate the changes relating to RROs. The app info must be copied to prevent
+ // affecting other parts of system server that may have cached this app info.
+ oldAppInfo = new ApplicationInfo(oldAppInfo);
+ oldAppInfo.overlayPaths = newAppInfo.overlayPaths.clone();
+ oldAppInfo.resourceDirs = newAppInfo.resourceDirs.clone();
+ provider.info.providerInfo.applicationInfo = oldAppInfo;
+
+ for (int j = 0, M = provider.widgets.size(); j < M; j++) {
+ Widget widget = provider.widgets.get(j);
+ if (widget.views != null) {
+ widget.views.updateAppInfo(oldAppInfo);
+ }
+ if (widget.maskedViews != null) {
+ widget.maskedViews.updateAppInfo(oldAppInfo);
+ }
+ }
+ }
+ }
+
/**
* Updates all providers with the specified package names, and records any providers that were
* pruned.
@@ -4875,5 +4926,14 @@
public void unlockUser(int userId) {
handleUserUnlocked(userId);
}
+
+ @Override
+ public void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
+ boolean updateFrameworkRes) {
+ synchronized (mLock) {
+ applyResourceOverlaysToWidgetsLocked(new HashSet<>(packageNames), userId,
+ updateFrameworkRes);
+ }
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 11df871..3540a33 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -98,6 +98,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -351,6 +352,8 @@
@Nullable
private ClientSuggestionsSession mClientSuggestionsSession;
+ private final AccessibilityManager mAccessibilityManager;
+
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -449,6 +452,7 @@
if (!mWaitForInlineRequest || mPendingInlineSuggestionsRequest != null) {
return;
}
+ mWaitForInlineRequest = inlineSuggestionsRequest != null;
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
maybeRequestFillFromServiceLocked();
viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
@@ -472,7 +476,10 @@
return;
}
- if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
+ // If a11y touch exploration is enabled, then we do not send an inline fill request
+ // to the regular af service, because dropdown UI is easier to use.
+ if (mPendingInlineSuggestionsRequest.isServiceSupported()
+ && !mAccessibilityManager.isTouchExplorationEnabled()) {
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
mPendingFillRequest.getClientState(),
@@ -941,6 +948,7 @@
mRemoteFillService = serviceComponentName == null ? null
: new RemoteFillService(context, serviceComponentName, userId, this,
bindInstantServiceAllowed);
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
mActivityToken = activityToken;
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 4127556..28a40eb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.companion;
+import static android.Manifest.permission.BIND_COMPANION_DEVICE_SERVICE;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
import static android.content.Context.BIND_IMPORTANT;
@@ -1234,6 +1235,12 @@
+ " has " + packageResolveInfos.size());
return new ServiceConnector.NoOp<>();
}
+ String servicePermission = packageResolveInfos.get(0).serviceInfo.permission;
+ if (!BIND_COMPANION_DEVICE_SERVICE.equals(servicePermission)) {
+ Slog.w(LOG_TAG, "Binding CompanionDeviceService must have "
+ + BIND_COMPANION_DEVICE_SERVICE + " permission.");
+ return new ServiceConnector.NoOp<>();
+ }
ComponentName componentName = packageResolveInfos.get(0).serviceInfo.getComponentName();
Slog.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
return new ServiceConnector.Impl<ICompanionDeviceService>(getContext(),
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 25ea12b..8a42ddf 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -70,6 +70,7 @@
import android.service.contentcapture.ActivityEvent.ActivityEventType;
import android.service.contentcapture.IDataShareCallback;
import android.service.contentcapture.IDataShareReadAdapter;
+import android.service.voice.VoiceInteractionManagerInternal;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Pair;
@@ -302,6 +303,37 @@
|| super.isDisabledLocked(userId);
}
+ @Override
+ protected void assertCalledByPackageOwner(@NonNull String packageName) {
+ try {
+ super.assertCalledByPackageOwner(packageName);
+ } catch (SecurityException e) {
+ final int callingUid = Binder.getCallingUid();
+
+ VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity
+ hotwordDetectionServiceIdentity =
+ LocalServices.getService(VoiceInteractionManagerInternal.class)
+ .getHotwordDetectionServiceIdentity();
+
+ if (callingUid != hotwordDetectionServiceIdentity.getIsolatedUid()) {
+ super.assertCalledByPackageOwner(packageName);
+ return;
+ }
+
+ final String[] packages =
+ getContext()
+ .getPackageManager()
+ .getPackagesForUid(hotwordDetectionServiceIdentity.getOwnerUid());
+ if (packages != null) {
+ for (String candidate : packages) {
+ if (packageName.equals(candidate)) return; // Found it
+ }
+ }
+
+ throw e;
+ }
+ }
+
private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
return mDisabledBySettings != null && mDisabledBySettings.get(userId);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 225a8d4..904def0 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -57,6 +57,7 @@
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.IDataShareCallback;
import android.service.contentcapture.SnapshotData;
+import android.service.voice.VoiceInteractionManagerInternal;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -415,12 +416,25 @@
}
if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
.hasRunningActivity(callingUid, packageName)) {
- final String[] packages = pm.getPackagesForUid(callingUid);
- final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
- Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
- + ") passed package (" + packageName + ") owned by UID " + packageUid);
- throw new SecurityException("Invalid package: " + packageName);
+ VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity
+ hotwordDetectionServiceIdentity =
+ LocalServices.getService(VoiceInteractionManagerInternal.class)
+ .getHotwordDetectionServiceIdentity();
+
+ boolean isHotwordDetectionServiceCall =
+ hotwordDetectionServiceIdentity != null
+ && callingUid == hotwordDetectionServiceIdentity.getIsolatedUid()
+ && packageUid == hotwordDetectionServiceIdentity.getOwnerUid();
+
+ if (!isHotwordDetectionServiceCall) {
+ final String[] packages = pm.getPackagesForUid(callingUid);
+ final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
+ Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
+ + ") passed package (" + packageName + ") owned by UID " + packageUid);
+
+ throw new SecurityException("Invalid package: " + packageName);
+ }
}
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 230e380..0621d0f 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -561,11 +561,6 @@
public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
int flags, int userId, int callingUid);
- /**
- * Resolves a content provider intent.
- */
- public abstract ProviderInfo resolveContentProvider(String name, int flags, int userId);
-
/**
* Resolves a content provider intent.
*/
@@ -845,7 +840,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/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b4912bb..31061190b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2509,6 +2509,16 @@
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions());
}
+ private boolean isBleState(int state) {
+ switch (state) {
+ case BluetoothAdapter.STATE_BLE_ON:
+ case BluetoothAdapter.STATE_BLE_TURNING_ON:
+ case BluetoothAdapter.STATE_BLE_TURNING_OFF:
+ return true;
+ }
+ return false;
+ }
+
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -2531,8 +2541,15 @@
sendBluetoothServiceDownCallback();
unbindAndFinish();
sendBleStateChanged(prevState, newState);
- // Don't broadcast as it has already been broadcast before
- isStandardBroadcast = false;
+
+ /* Currently, the OFF intent is broadcasted externally only when we transition
+ * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state,
+ * we are guaranteed that the OFF intent has been broadcasted earlier and we
+ * can safely skip it.
+ * Conversely, if the previous state is not a BLE state, it indicates that some
+ * sort of crash has occurred, moving us directly to STATE_OFF without ever
+ * passing through BLE_ON. We should broadcast the OFF intent in this case. */
+ isStandardBroadcast = !isBleState(prevState);
} else if (!intermediate_off) {
// connect to GattService
@@ -2585,6 +2602,11 @@
// Show prevState of BLE_ON as OFF to standard users
prevState = BluetoothAdapter.STATE_OFF;
}
+ if (DBG) {
+ Slog.d(TAG,
+ "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
+ + BluetoothAdapter.nameForState(newState));
+ }
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
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/PermissionThread.java b/services/core/java/com/android/server/PermissionThread.java
new file mode 100644
index 0000000..cf444fa
--- /dev/null
+++ b/services/core/java/com/android/server/PermissionThread.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.server;
+
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.Trace;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.ServiceThread;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Shared singleton thread for the system. This is a thread for handling
+ * calls to and from the PermissionController and handling synchronization
+ * between permissions and appops states.
+ */
+public final class PermissionThread extends ServiceThread {
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
+
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static PermissionThread sInstance;
+ private static Handler sHandler;
+ private static HandlerExecutor sHandlerExecutor;
+
+ private PermissionThread() {
+ super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance != null) {
+ return;
+ }
+
+ sInstance = new PermissionThread();
+ sInstance.start();
+ final Looper looper = sInstance.getLooper();
+ looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ looper.setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
+ sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
+ }
+
+ public static PermissionThread get() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+
+ public static Executor getExecutor() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e336b6b..16645df 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -375,15 +375,38 @@
try {
FileChannel channel = getBlockOutputChannel();
+ // Format the data selectively.
+ //
+ // 1. write header, set length = 0
int header_size = DIGEST_SIZE_BYTES + HEADER_SIZE;
ByteBuffer buf = ByteBuffer.allocate(header_size);
buf.put(new byte[DIGEST_SIZE_BYTES]);
buf.putInt(PARTITION_TYPE_MARKER);
buf.putInt(0);
+ buf.flip();
channel.write(buf);
- // corrupt the payload explicitly
+ channel.force(true);
+
+ // 2. corrupt the legacy FRP data explicitly
int payload_size = (int) getBlockDeviceSize() - header_size;
- buf = ByteBuffer.allocate(payload_size);
+ buf = ByteBuffer.allocate(payload_size
+ - TEST_MODE_RESERVED_SIZE - FRP_CREDENTIAL_RESERVED_SIZE - 1);
+ channel.write(buf);
+ channel.force(true);
+
+ // 3. skip the test mode data and leave it unformat
+ // This is for a feature that enables testing.
+ channel.position(channel.position() + TEST_MODE_RESERVED_SIZE);
+
+ // 4. wipe the FRP_CREDENTIAL explicitly
+ buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
+ channel.write(buf);
+ channel.force(true);
+
+ // 5. set unlock = 0 because it's a formatPartitionLocked
+ buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
+ buf.put((byte)0);
+ buf.flip();
channel.write(buf);
channel.force(true);
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index e4a30ad5..28fb374 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -21,7 +21,6 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.RunningServiceInfo;
import static android.app.ActivityManager.RunningTaskInfo;
-import static android.app.ActivityManager.getCurrentUser;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
@@ -232,14 +231,14 @@
public void onUserStarting(TargetUser user) {
if (mCurrentUser == -1) {
mCurrentUser = user.getUserIdentifier();
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.userSwitching(-1, user.getUserIdentifier());
}
}
@Override
public void onUserSwitching(TargetUser from, TargetUser to) {
mCurrentUser = to.getUserIdentifier();
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.userSwitching(from.getUserIdentifier(), to.getUserIdentifier());
}
class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
@@ -718,6 +717,9 @@
public void setIndividualSensorPrivacy(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
return;
}
@@ -843,6 +845,9 @@
public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -896,17 +901,24 @@
@Override
public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
enforceObserveSensorPrivacyPermission();
- synchronized (mLock) {
- SparseArray<SensorState> states = mIndividualEnabled.get(userId);
- if (states == null) {
- return false;
- }
- SensorState state = states.get(sensor);
- if (state == null) {
- return false;
- }
- return state.mEnabled;
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
}
+ synchronized (mLock) {
+ return isIndividualSensorPrivacyEnabledLocked(userId, sensor);
+ }
+ }
+
+ private boolean isIndividualSensorPrivacyEnabledLocked(int userId, int sensor) {
+ SparseArray<SensorState> states = mIndividualEnabled.get(userId);
+ if (states == null) {
+ return false;
+ }
+ SensorState state = states.get(sensor);
+ if (state == null) {
+ return false;
+ }
+ return state.mEnabled;
}
/**
@@ -1149,11 +1161,27 @@
ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
- throw new NullPointerException("listener cannot be null");
+ throw new IllegalArgumentException("listener cannot be null");
}
mHandler.addListener(userId, sensor, listener);
}
+
+ /**
+ * Registers a listener to be notified when the sensor privacy state changes. The callback
+ * can be called if the user changes and the setting is different between the transitioning
+ * users.
+ */
+ @Override
+ public void addUserGlobalIndividualSensorPrivacyListener(int sensor,
+ ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
+ if (listener == null) {
+ throw new IllegalArgumentException("listener cannot be null");
+ }
+ mHandler.addUserGlobalListener(sensor, listener);
+ }
+
/**
* Unregisters a listener from sensor privacy state change notifications.
*/
@@ -1174,15 +1202,28 @@
ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
- throw new NullPointerException("listener cannot be null");
+ throw new IllegalArgumentException("listener cannot be null");
}
mHandler.removeListener(sensor, listener);
}
@Override
+ public void removeUserGlobalIndividualSensorPrivacyListener(int sensor,
+ ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
+ if (listener == null) {
+ throw new IllegalArgumentException("listener cannot be null");
+ }
+ mHandler.removeUserGlobalListener(sensor, listener);
+ }
+
+ @Override
public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
Objects.requireNonNull(token);
Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId));
@@ -1209,6 +1250,40 @@
}
}
+ private void userSwitching(int from, int to) {
+ boolean micState;
+ boolean camState;
+ boolean prevMicState;
+ boolean prevCamState;
+ synchronized (mLock) {
+ prevMicState = isIndividualSensorPrivacyEnabledLocked(from, MICROPHONE);
+ prevCamState = isIndividualSensorPrivacyEnabledLocked(from, CAMERA);
+ micState = isIndividualSensorPrivacyEnabledLocked(to, MICROPHONE);
+ camState = isIndividualSensorPrivacyEnabledLocked(to, CAMERA);
+ }
+ if (prevMicState != micState) {
+ mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState);
+ setGlobalRestriction(MICROPHONE, micState);
+ }
+ if (prevCamState != camState) {
+ mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState);
+ setGlobalRestriction(CAMERA, micState);
+ }
+ }
+
+ private void setGlobalRestriction(int sensor, boolean enabled) {
+ switch(sensor) {
+ case MICROPHONE:
+ mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled,
+ mAppOpsRestrictionToken);
+ break;
+ case CAMERA:
+ mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
+ mAppOpsRestrictionToken);
+ break;
+ }
+ }
+
/**
* Remove a sensor use reminder suppression token.
*
@@ -1454,7 +1529,12 @@
@GuardedBy("mListenerLock")
private final SparseArray<SparseArray<RemoteCallbackList<ISensorPrivacyListener>>>
mIndividualSensorListeners = new SparseArray<>();
- private final ArrayMap<ISensorPrivacyListener, DeathRecipient> mDeathRecipients;
+ @GuardedBy("mListenerLock")
+ private final SparseArray<RemoteCallbackList<ISensorPrivacyListener>>
+ mUserGlobalIndividualSensorListeners = new SparseArray<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>>
+ mDeathRecipients;
private final Context mContext;
SensorPrivacyHandler(Looper looper, Context context) {
@@ -1479,18 +1559,22 @@
mSensorPrivacyServiceImpl));
}
+ public void onUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
+ sendMessage(PooledLambda.obtainMessage(
+ SensorPrivacyHandler::handleUserGlobalSensorPrivacyChanged,
+ this, sensor, enabled));
+ }
+
public void addListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = new DeathRecipient(listener);
- mDeathRecipients.put(listener, deathRecipient);
- mListeners.register(listener);
+ if (mListeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
}
}
public void addListener(int userId, int sensor, ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = new DeathRecipient(listener);
- mDeathRecipients.put(listener, deathRecipient);
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
if (listenersForUser == null) {
@@ -1502,32 +1586,55 @@
listeners = new RemoteCallbackList<>();
listenersForUser.put(sensor, listeners);
}
- listeners.register(listener);
+ if (listeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
+ }
+ }
+
+ public void addUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
+ synchronized (mListenerLock) {
+ RemoteCallbackList<ISensorPrivacyListener> listeners =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+ if (listeners == null) {
+ listeners = new RemoteCallbackList<>();
+ mUserGlobalIndividualSensorListeners.put(sensor, listeners);
+ }
+ if (listeners.register(listener)) {
+ addDeathRecipient(listener);
+ }
}
}
public void removeListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = mDeathRecipients.remove(listener);
- if (deathRecipient != null) {
- deathRecipient.destroy();
+ if (mListeners.unregister(listener)) {
+ removeDeathRecipient(listener);
}
- mListeners.unregister(listener);
}
}
public void removeListener(int sensor, ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- DeathRecipient deathRecipient = mDeathRecipients.remove(listener);
- if (deathRecipient != null) {
- deathRecipient.destroy();
- }
-
for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
RemoteCallbackList callbacks =
mIndividualSensorListeners.valueAt(i).get(sensor);
if (callbacks != null) {
- callbacks.unregister(listener);
+ if (callbacks.unregister(listener)) {
+ removeDeathRecipient(listener);
+ }
+ }
+ }
+ }
+ }
+
+ public void removeUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
+ synchronized (mListenerLock) {
+ RemoteCallbackList callbacks =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+ if (callbacks != null) {
+ if (callbacks.unregister(listener)) {
+ removeDeathRecipient(listener);
}
}
}
@@ -1551,9 +1658,12 @@
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
- setGlobalRestriction();
if (userId == mCurrentUser) {
- setGlobalRestriction();
+ mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, enabled);
+ }
+
+ if (userId == mCurrentUser) {
+ onUserGlobalSensorPrivacyChanged(sensor, enabled);
}
if (listenersForUser == null) {
@@ -1563,16 +1673,42 @@
if (listeners == null) {
return;
}
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ try {
+ final int count = listeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
+ try {
+ listener.onSensorPrivacyChanged(enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ }
}
+ } finally {
+ listeners.finishBroadcast();
}
- listeners.finishBroadcast();
+ }
+
+ public void handleUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
+ RemoteCallbackList<ISensorPrivacyListener> listeners =
+ mUserGlobalIndividualSensorListeners.get(sensor);
+
+ if (listeners == null) {
+ return;
+ }
+
+ try {
+ final int count = listeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
+ try {
+ listener.onSensorPrivacyChanged(enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ }
+ }
+ } finally {
+ listeners.finishBroadcast();
+ }
}
public void removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key,
@@ -1581,20 +1717,33 @@
SensorPrivacyServiceImpl::removeSuppressPackageReminderToken,
mSensorPrivacyServiceImpl, key, token));
}
- }
- private void setGlobalRestriction() {
- boolean camState =
- mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, CAMERA);
- boolean micState =
- mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE);
+ private void addDeathRecipient(ISensorPrivacyListener listener) {
+ Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener);
+ if (deathRecipient == null) {
+ deathRecipient = new Pair<>(new DeathRecipient(listener), 1);
+ } else {
+ int newRefCount = deathRecipient.second + 1;
+ deathRecipient = new Pair<>(deathRecipient.first, newRefCount);
+ }
+ mDeathRecipients.put(listener, deathRecipient);
+ }
- mAppOpsManagerInternal
- .setGlobalRestriction(OP_CAMERA, camState, mAppOpsRestrictionToken);
- mAppOpsManagerInternal
- .setGlobalRestriction(OP_RECORD_AUDIO, micState, mAppOpsRestrictionToken);
+ private void removeDeathRecipient(ISensorPrivacyListener listener) {
+ Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener);
+ if (deathRecipient == null) {
+ return;
+ } else {
+ int newRefCount = deathRecipient.second - 1;
+ if (newRefCount == 0) {
+ mDeathRecipients.remove(listener);
+ deathRecipient.first.destroy();
+ return;
+ }
+ deathRecipient = new Pair<>(deathRecipient.first, newRefCount);
+ }
+ mDeathRecipients.put(listener, deathRecipient);
+ }
}
private final class DeathRecipient implements IBinder.DeathRecipient {
@@ -1760,9 +1909,9 @@
if (!mIsInEmergencyCall) {
mIsInEmergencyCall = true;
if (mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(getCurrentUser(), MICROPHONE)) {
+ .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- getCurrentUser(), OTHER, MICROPHONE, false);
+ mCurrentUser, OTHER, MICROPHONE, false);
mMicUnmutedForEmergencyCall = true;
} else {
mMicUnmutedForEmergencyCall = false;
@@ -1777,7 +1926,7 @@
mIsInEmergencyCall = false;
if (mMicUnmutedForEmergencyCall) {
mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- getCurrentUser(), OTHER, MICROPHONE, true);
+ mCurrentUser, OTHER, MICROPHONE, true);
mMicUnmutedForEmergencyCall = false;
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index ab6b8a2..b9de1018 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1032,7 +1032,7 @@
final ProviderInfo provider = mPmInternal.resolveContentProvider(
MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- user.id);
+ user.id, Process.SYSTEM_UID);
if (provider != null) {
final IActivityManager am = ActivityManager.getService();
try {
@@ -2021,7 +2021,7 @@
return mPmInternal.resolveContentProvider(
authority, PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.getUserId(UserHandle.USER_SYSTEM));
+ UserHandle.getUserId(UserHandle.USER_SYSTEM), Process.SYSTEM_UID);
}
private void updateLegacyStorageApps(String packageName, int uid, boolean hasLegacy) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6129100..35ed477 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -193,6 +193,7 @@
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -16657,6 +16658,13 @@
if (updateFrameworkRes) {
ParsingPackageUtils.readConfigUseRoundIcon(null);
}
+
+ AppWidgetManagerInternal widgets = LocalServices.getService(AppWidgetManagerInternal.class);
+ if (widgets != null) {
+ widgets.applyResourceOverlaysToWidgets(new HashSet<>(packagesToUpdate), userId,
+ updateFrameworkRes);
+ }
+
mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
if (updateFrameworkRes) {
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/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 399a245..60530a3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -841,6 +841,12 @@
public void noteEvent(final int code, final String name, final int uid) {
enforceCallingPermission();
+ if (name == null) {
+ // TODO(b/194733136): Replace with an IllegalArgumentException throw.
+ Slog.wtfStack(TAG, "noteEvent called with null name. code = " + code);
+ return;
+ }
+
synchronized (mLock) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9dbb707..7c336d7 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.ProcLocksReader;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.ServiceThread;
@@ -319,6 +320,7 @@
private int mPersistentCompactionCount;
private int mBfgsCompactionCount;
private final ProcessDependencies mProcessDependencies;
+ private final ProcLocksReader mProcLocksReader;
public CachedAppOptimizer(ActivityManagerService am) {
this(am, null, new DefaultProcessDependencies());
@@ -335,6 +337,7 @@
mProcessDependencies = processDependencies;
mTestCallback = callback;
mSettingsObserver = new SettingsContentObserver();
+ mProcLocksReader = new ProcLocksReader();
}
/**
@@ -1312,7 +1315,7 @@
try {
// pre-check for locks to avoid unnecessary freeze/unfreeze operations
- if (Process.hasFileLocks(pid)) {
+ if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
}
@@ -1399,7 +1402,7 @@
try {
// post-check to prevent races
- if (Process.hasFileLocks(pid)) {
+ if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
}
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 1ecb9eb..598f086 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -50,7 +50,7 @@
* Used to hold the data for the statsd atoms logging
* Must be in sync with statslog.h
*/
- private static final int LMKD_REPLY_MAX_SIZE = 214;
+ private static final int LMKD_REPLY_MAX_SIZE = 222;
// connection listener interface
interface LmkdConnectionListener {
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index a8d0582..9158891 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -64,11 +64,14 @@
final int freeMemKb = inputData.readInt();
final int freeSwapKb = inputData.readInt();
final int killReason = inputData.readInt();
+ final int thrashing = inputData.readInt();
+ final int maxThrashing = inputData.readInt();
final String procName = inputData.readUTF();
FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
- minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason));
+ minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason), thrashing,
+ maxThrashing);
} catch (IOException e) {
Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
return;
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index 4f3438fe..b07684c 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);
@@ -365,6 +365,9 @@
private int onPhantomProcessFdEvent(FileDescriptor fd, int events) {
synchronized (mLock) {
final PhantomProcessRecord proc = mPhantomProcessesPidFds.get(fd.getInt$());
+ if (proc == null) {
+ return 0;
+ }
if ((events & EVENT_INPUT) != 0) {
proc.onProcDied(true);
} else {
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 6b7787a..b1d300c 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1103,9 +1103,13 @@
}
public boolean isAdvancedCoexLogicEnabled(Context context) {
- return (Build.IS_USERDEBUG || Build.IS_ENG)
- && Settings.Secure.getInt(context.getContentResolver(),
- CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0;
+ return Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
+ }
+
+ public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
}
}
@@ -1138,6 +1142,8 @@
// by default.
CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
+ coexCoordinator.setFaceHapticDisabledWhenNonBypass(
+ injector.isCoexFaceNonBypassHapticsDisabled(context));
try {
injector.getActivityManagerService().registerUserSwitchObserver(
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..f4327e8 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,24 @@
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 to start (such as finger lift & re-touch)
+ public static final int STATE_STARTED_PAUSED = 2;
+ // Same as above, except auth was attempted (rejected, timed out, etc).
+ public static final int STATE_STARTED_PAUSED_ATTEMPTED = 3;
+ // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
+ public static final int STATE_STOPPED = 4;
+
+ @IntDef({STATE_NEW,
+ STATE_STARTED,
+ STATE_STARTED_PAUSED,
+ STATE_STARTED_PAUSED_ATTEMPTED,
+ STATE_STOPPED})
+ @interface State {}
+
private final boolean mIsStrongBiometric;
private final boolean mRequireConfirmation;
private final ActivityTaskManager mActivityTaskManager;
@@ -56,6 +76,7 @@
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
+ private final boolean mIsKeyguardBypassEnabled;
protected final long mOperationId;
@@ -63,13 +84,27 @@
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,
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
- boolean shouldVibrate) {
+ boolean shouldVibrate, boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE,
statsClient);
@@ -82,6 +117,7 @@
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
+ mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -221,7 +257,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 +299,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 +314,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 +333,11 @@
vibrateError();
}
}
+
+ @Override
+ public void handleLifecycleAfterAuth() {
+ AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
+ }
});
}
}
@@ -307,6 +354,12 @@
}
}
+ @Override
+ public void onError(int errorCode, int vendorCode) {
+ super.onError(errorCode, vendorCode);
+ mState = STATE_STOPPED;
+ }
+
/**
* Start authentication
*/
@@ -345,6 +398,18 @@
}
}
+ public @State int getState() {
+ return mState;
+ }
+
+ /**
+ * @return true if the client supports bypass (e.g. passive auth such as face), and if it's
+ * enabled by the user.
+ */
+ public boolean isKeyguardBypassEnabled() {
+ return mIsKeyguardBypassEnabled;
+ }
+
@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 1ac9167..b20316e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -355,7 +355,6 @@
/**
* Creates a new scheduler.
- * @param context system_server context.
* @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
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 7638a51..a15ecad 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -22,12 +22,16 @@
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.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;
/**
@@ -41,8 +45,13 @@
private static final String TAG = "BiometricCoexCoordinator";
public static final String SETTING_ENABLE_NAME =
"com.android.server.biometrics.sensors.CoexCoordinator.enable";
+ public static final String FACE_HAPTIC_DISABLE =
+ "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics";
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.
@@ -58,10 +67,69 @@
* 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.
*/
@@ -78,6 +146,10 @@
mAdvancedLogicEnabled = enabled;
}
+ public void setFaceHapticDisabledWhenNonBypass(boolean disabled) {
+ mFaceHapticDisabledWhenNonBypass = disabled;
+ }
+
@VisibleForTesting
void reset() {
mClientMap.clear();
@@ -85,11 +157,16 @@
// SensorType to AuthenticationClient map
private final Map<Integer, AuthenticationClient<?>> mClientMap;
+ @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
private boolean mAdvancedLogicEnabled;
+ private boolean mFaceHapticDisabledWhenNonBypass;
+ 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,
@@ -121,34 +198,47 @@
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 */);
+ 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 (isPointerDown(udfps)) {
- // Face auth success while UDFPS pointer down. No callback, no haptic.
- // Feedback will be provided after UDFPS result.
+ 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();
+ if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+ Slog.w(TAG, "Skipping face success haptic");
+ } else {
+ callback.sendHapticFeedback();
+ }
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
}
} else if (isCurrentUdfps(client)) {
if (isFaceScanning()) {
@@ -156,8 +246,17 @@
// Cancel face auth and/or prevent it from invoking haptics/callbacks after
face.cancel();
}
+
+ removeAndFinishAllFaceFromQueue();
+
callback.sendHapticFeedback();
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
+ } else {
+ // Capacitive fingerprint sensor (or other)
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
}
}
} else {
@@ -165,13 +264,86 @@
// 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 if (isUdfpsAuthAttempted(udfps)) {
+ // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still
+ // auth after pointer goes down, it means UDFPS encountered a rejection. In
+ // this case, we need to play the final reject haptic since face auth is
+ // also done now.
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
+ else {
+ // UDFPS auth has never been attempted.
+ if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+ Slog.w(TAG, "Skipping face reject haptic");
+ } else {
+ 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"
@@ -180,6 +352,30 @@
}
}
+ @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);
}
@@ -189,12 +385,20 @@
}
private boolean isFaceScanning() {
- return mClientMap.containsKey(SENSOR_TYPE_FACE);
+ AuthenticationClient<?> client = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
+ return client != null && client.getState() == AuthenticationClient.STATE_STARTED;
}
- private static boolean isPointerDown(@Nullable AuthenticationClient<?> client) {
+ private static boolean isUdfpsActivelyAuthing(@Nullable AuthenticationClient<?> client) {
if (client instanceof Udfps) {
- return ((Udfps) client).isPointerDown();
+ return client.getState() == AuthenticationClient.STATE_STARTED;
+ }
+ return false;
+ }
+
+ private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) {
+ if (client instanceof Udfps) {
+ return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED;
}
return false;
}
@@ -221,7 +425,16 @@
return true;
}
+ @Override
public String toString() {
- return "Enabled: " + mAdvancedLogicEnabled;
+ StringBuilder sb = new StringBuilder();
+ sb.append("Enabled: ").append(mAdvancedLogicEnabled);
+ sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass);
+ 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/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
index c8867ea..b4c82f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -48,6 +48,64 @@
private boolean mLightSensorEnabled = false;
private boolean mShouldLogMetrics = true;
+ /**
+ * Probe for loggable attributes that can be continuously monitored, such as ambient light.
+ *
+ * Disable probes when the sensors are in states that are not interesting for monitoring
+ * purposes to save power.
+ */
+ protected interface Probe {
+ /** Ensure the probe is actively sampling for new data. */
+ void enable();
+ /** Stop sampling data. */
+ void disable();
+ }
+
+ /**
+ * Client monitor callback that exposes a probe.
+ *
+ * Disables the probe when the operation completes.
+ */
+ protected static class CallbackWithProbe<T extends Probe>
+ implements BaseClientMonitor.Callback {
+ private final boolean mStartWithClient;
+ private final T mProbe;
+
+ public CallbackWithProbe(@NonNull T probe, boolean startWithClient) {
+ mProbe = probe;
+ mStartWithClient = startWithClient;
+ }
+
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+ if (mStartWithClient) {
+ mProbe.enable();
+ }
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
+ mProbe.disable();
+ }
+
+ @NonNull
+ public T getProbe() {
+ return mProbe;
+ }
+ }
+
+ private class ALSProbe implements Probe {
+ @Override
+ public void enable() {
+ setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
+ }
+
+ @Override
+ public void disable() {
+ setLightSensorLoggingEnabled(null);
+ }
+ }
+
// report only the most recent value
// consider com.android.server.display.utils.AmbientFilter or similar if need arises
private volatile float mLastAmbientLux = 0;
@@ -285,21 +343,17 @@
return latency;
}
- /** Get a callback to start/stop ALS capture when client runs. */
+ /**
+ * Get a callback to start/stop ALS capture when client runs.
+ *
+ * If the probe should not run for the entire operation, do not set startWithClient and
+ * start/stop the problem when needed.
+ *
+ * @param startWithClient if probe should start automatically when the operation starts.
+ */
@NonNull
- protected BaseClientMonitor.Callback createALSCallback() {
- return new BaseClientMonitor.Callback() {
- @Override
- public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
- }
-
- @Override
- public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
- boolean success) {
- setLightSensorLoggingEnabled(null);
- }
- };
+ protected CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) {
+ return new CallbackWithProbe<>(new ALSProbe(), startWithClient);
}
/** The sensor to use for ALS logging. */
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..12d6b08 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
@@ -252,7 +251,8 @@
@Override // Binder call
public void authenticate(final IBinder token, final long operationId, int userId,
- final IFaceServiceReceiver receiver, final String opPackageName) {
+ final IFaceServiceReceiver receiver, final String opPackageName,
+ boolean isKeyguardBypassEnabled) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
@@ -276,7 +276,7 @@
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
- statsClient, isKeyguard);
+ statsClient, isKeyguard, isKeyguardBypassEnabled);
}
@Override // Binder call
@@ -319,10 +319,12 @@
return;
}
+ final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
}
@Override // Binder call
@@ -703,5 +705,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..93ab1b6 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);
@@ -110,7 +110,7 @@
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication);
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
void cancelAuthentication(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..f7fd8d0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -69,11 +69,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
- @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication) {
+ @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
@@ -89,10 +91,16 @@
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) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
@@ -128,10 +136,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 +157,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..a806277 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,8 @@
@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(true /* startWithClient */), callback);
}
@Override
@@ -153,22 +155,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 +181,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 +201,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..718b9da 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;
@@ -378,7 +378,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
@@ -386,7 +386,7 @@
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
- allowBackgroundAuthentication);
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
scheduleForSensor(sensorId, client);
});
}
@@ -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/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..d05333d 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
@@ -620,7 +622,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -628,7 +630,8 @@
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
- statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication);
+ statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client);
});
}
@@ -858,8 +861,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..c33b957 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
@@ -61,11 +61,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
- @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication) {
+ @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
final Resources resources = getContext().getResources();
@@ -79,10 +81,16 @@
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) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
@@ -115,10 +123,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 +144,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..80828cced 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()
@@ -71,7 +69,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
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 639814b..8835c1e0 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,6 +54,9 @@
@NonNull private final LockoutCache mLockoutCache;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
+ @NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
+
@Nullable private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -69,15 +72,37 @@
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
+ mSensorProps = sensorProps;
+ mALSProbeCallback = createALSCallback(false /* startWithClient */);
+ }
+
+ @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
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(mALSProbeCallback, callback);
+ }
+
+ @Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+ if (authenticated) {
+ mCallback.onClientFinished(this, true /* success */);
+ }
}
@Override
@@ -86,8 +111,10 @@
super.onAuthenticated(identifier, authenticated, token);
if (authenticated) {
+ mState = STATE_STOPPED;
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
- mCallback.onClientFinished(this, true /* success */);
+ } else {
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
}
}
@@ -145,7 +172,10 @@
public void onPointerDown(int x, int y, float minor, float major) {
try {
mIsPointerDown = true;
+ mState = STATE_STARTED;
+ mALSProbeCallback.getProbe().enable();
getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
+
if (getListener() != null) {
getListener().onUdfpsPointerDown(getSensorId());
}
@@ -158,7 +188,10 @@
public void onPointerUp() {
try {
mIsPointerDown = false;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
+ mALSProbeCallback.getProbe().disable();
getFreshDaemon().onPointerUp(0 /* pointerId */);
+
if (getListener() != null) {
getListener().onUdfpsPointerUp(getSensorId());
}
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 e8200af..c420c5c 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
@@ -84,7 +84,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
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/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 95a54d3..83f1480 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;
+ @NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
+
private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context,
@@ -62,19 +66,35 @@
@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 */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
+ mSensorProps = sensorProps;
+ mALSProbeCallback = createALSCallback(false /* startWithClient */);
+ }
+
+ @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
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(mALSProbeCallback, callback);
}
@Override
@@ -88,10 +108,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_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
@@ -125,6 +146,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);
@@ -162,7 +190,10 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
mIsPointerDown = true;
+ mState = STATE_STARTED;
+ mALSProbeCallback.getProbe().enable();
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
+
if (getListener() != null) {
try {
getListener().onUdfpsPointerDown(getSensorId());
@@ -175,7 +206,10 @@
@Override
public void onPointerUp() {
mIsPointerDown = false;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
+ mALSProbeCallback.getProbe().disable();
UdfpsHelper.onFingerUp(getFreshDaemon());
+
if (getListener() != null) {
try {
getListener().onUdfpsPointerUp(getSensorId());
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 250e132..dc70534 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
@@ -77,7 +77,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
+ return new CompositeCallback(createALSCallback(true /* startWithClient */), callback);
}
@Override
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 54a4ad4..23f0ffb 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -52,11 +52,11 @@
public BroadcastRadioService(Context context) {
super(context);
- mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService();
+ mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
mV1Modules = mHal1.loadModules();
OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
- max.isPresent() ? max.getAsInt() + 1 : 0);
+ max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
}
@Override
@@ -111,7 +111,7 @@
synchronized (mLock) {
if (!mHal2.hasAnyModules()) {
Slog.i(TAG, "There are no HAL 2.x modules registered");
- return new AnnouncementAggregator(listener);
+ return new AnnouncementAggregator(listener, mLock);
}
return mHal2.addAnnouncementListener(enabledTypes, listener);
diff --git a/services/core/java/com/android/server/broadcastradio/OWNERS b/services/core/java/com/android/server/broadcastradio/OWNERS
index ea4421e..3e360e7 100644
--- a/services/core/java/com/android/server/broadcastradio/OWNERS
+++ b/services/core/java/com/android/server/broadcastradio/OWNERS
@@ -1,2 +1,3 @@
+keunyoung@google.com
+oscarazu@google.com
twasilczyk@google.com
-randolphs@google.com
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
index e8ac547..5da6032 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
@@ -17,16 +17,9 @@
package com.android.server.broadcastradio.hal1;
import android.annotation.NonNull;
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.radio.IRadioService;
import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.RadioManager;
-import android.os.ParcelableException;
-
-import com.android.server.SystemService;
import java.util.List;
import java.util.Objects;
@@ -37,7 +30,7 @@
*/
private final long mNativeContext = nativeInit();
- private final Object mLock = new Object();
+ private final Object mLock;
@Override
protected void finalize() throws Throwable {
@@ -51,6 +44,14 @@
private native Tuner nativeOpenTuner(long nativeContext, int moduleId,
RadioManager.BandConfig config, boolean withAudio, ITunerCallback callback);
+ /**
+ * Constructor. should pass
+ * {@code com.android.server.broadcastradio.BroadcastRadioService#mLock} for lock.
+ */
+ public BroadcastRadioService(@NonNull Object lock) {
+ mLock = lock;
+ }
+
public @NonNull List<RadioManager.ModuleProperties> loadModules() {
synchronized (mLock) {
return Objects.requireNonNull(nativeLoadModules(mNativeContext));
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
index 5307697..42e296f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
@@ -35,7 +35,7 @@
public class AnnouncementAggregator extends ICloseHandle.Stub {
private static final String TAG = "BcRadio2Srv.AnnAggr";
- private final Object mLock = new Object();
+ private final Object mLock;
@NonNull private final IAnnouncementListener mListener;
private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient();
@@ -45,8 +45,9 @@
@GuardedBy("mLock")
private boolean mIsClosed = false;
- public AnnouncementAggregator(@NonNull IAnnouncementListener listener) {
+ public AnnouncementAggregator(@NonNull IAnnouncementListener listener, @NonNull Object lock) {
mListener = Objects.requireNonNull(listener);
+ mLock = Objects.requireNonNull(lock);
try {
listener.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 5e79c59..5c07f76 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -42,7 +42,7 @@
public class BroadcastRadioService {
private static final String TAG = "BcRadio2Srv";
- private final Object mLock = new Object();
+ private final Object mLock;
@GuardedBy("mLock")
private int mNextModuleId = 0;
@@ -68,7 +68,7 @@
moduleId = mNextModuleId;
}
- RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName);
+ RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName, mLock);
if (module == null) {
return;
}
@@ -116,8 +116,9 @@
}
};
- public BroadcastRadioService(int nextModuleId) {
+ public BroadcastRadioService(int nextModuleId, Object lock) {
mNextModuleId = nextModuleId;
+ mLock = lock;
try {
IServiceManager manager = IServiceManager.getService();
if (manager == null) {
@@ -174,7 +175,7 @@
public ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
@NonNull IAnnouncementListener listener) {
- AnnouncementAggregator aggregator = new AnnouncementAggregator(listener);
+ AnnouncementAggregator aggregator = new AnnouncementAggregator(listener, mLock);
boolean anySupported = false;
synchronized (mLock) {
for (RadioModule module : mModules.values()) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index b7e188c..ef7f4c9 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -58,7 +58,7 @@
@NonNull private final IBroadcastRadio mService;
@NonNull public final RadioManager.ModuleProperties mProperties;
- private final Object mLock = new Object();
+ private final Object mLock;
@NonNull private final Handler mHandler;
@GuardedBy("mLock")
@@ -132,13 +132,15 @@
@VisibleForTesting
RadioModule(@NonNull IBroadcastRadio service,
- @NonNull RadioManager.ModuleProperties properties) {
+ @NonNull RadioManager.ModuleProperties properties, @NonNull Object lock) {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
+ mLock = Objects.requireNonNull(lock);
mHandler = new Handler(Looper.getMainLooper());
}
- public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
+ public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName,
+ Object lock) {
try {
IBroadcastRadio service = IBroadcastRadio.getService(fqName);
if (service == null) return null;
@@ -156,7 +158,7 @@
RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
service.getProperties(), amfmConfig.value, dabConfig.value);
- return new RadioModule(service, prop);
+ return new RadioModule(service, prop, lock);
} catch (RemoteException ex) {
Slog.e(TAG, "failed to load module " + fqName, ex);
return null;
@@ -178,7 +180,8 @@
});
mHalTunerSession = Objects.requireNonNull(hwSession.value);
}
- TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb);
+ TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb,
+ mLock);
mAidlTunerSessions.add(tunerSession);
// Propagate state to new client. Note: These callbacks are invoked while holding mLock
@@ -377,7 +380,7 @@
}
};
- synchronized (mService) {
+ synchronized (mLock) {
mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
halResult.value = result;
hwCloseHandle.value = closeHnd;
@@ -401,7 +404,7 @@
if (id == 0) throw new IllegalArgumentException("Image ID is missing");
byte[] rawImage;
- synchronized (mService) {
+ synchronized (mLock) {
List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
rawImage = new byte[rawList.size()];
for (int i = 0; i < rawList.size(); i++) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 7ab3bdd..200af2f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -40,7 +40,7 @@
private static final String TAG = "BcRadio2Srv.session";
private static final String kAudioDeviceName = "Radio tuner source";
- private final Object mLock = new Object();
+ private final Object mLock;
private final RadioModule mModule;
private final ITunerSession mHwSession;
@@ -53,10 +53,12 @@
private RadioManager.BandConfig mDummyConfig = null;
TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
- @NonNull android.hardware.radio.ITunerCallback callback) {
+ @NonNull android.hardware.radio.ITunerCallback callback,
+ @NonNull Object lock) {
mModule = Objects.requireNonNull(module);
mHwSession = Objects.requireNonNull(hwSession);
mCallback = Objects.requireNonNull(callback);
+ mLock = Objects.requireNonNull(lock);
}
@Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 56b68b7..eed68f8 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -27,7 +27,9 @@
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* ShellCommands for {@link DeviceStateManagerService}.
@@ -56,14 +58,18 @@
switch (cmd) {
case "state":
return runState(pw);
+ case "print-state":
+ return runPrintState(pw);
case "print-states":
return runPrintStates(pw);
+ case "print-states-simple":
+ return runPrintStatesSimple(pw);
default:
return handleDefaultCommands(cmd);
}
}
- private void printState(PrintWriter pw) {
+ private void printAllStates(PrintWriter pw) {
Optional<DeviceState> committedState = mService.getCommittedState();
Optional<DeviceState> baseState = mService.getBaseState();
Optional<DeviceState> overrideState = mService.getOverrideState();
@@ -79,7 +85,8 @@
private int runState(PrintWriter pw) {
final String nextArg = getNextArg();
if (nextArg == null) {
- printState(pw);
+ printAllStates(pw);
+ return 0;
}
final Context context = mService.getContext();
@@ -123,6 +130,16 @@
return 0;
}
+ private int runPrintState(PrintWriter pw) {
+ Optional<DeviceState> deviceState = mService.getCommittedState();
+ if (deviceState.isPresent()) {
+ pw.println(deviceState.get().getIdentifier());
+ return 0;
+ }
+ getErrPrintWriter().println("Error: device state not available.");
+ return 1;
+ }
+
private int runPrintStates(PrintWriter pw) {
DeviceState[] states = mService.getSupportedStates();
pw.print("Supported states: [\n");
@@ -133,6 +150,14 @@
return 0;
}
+ private int runPrintStatesSimple(PrintWriter pw) {
+ pw.print(Arrays.stream(mService.getSupportedStates())
+ .map(DeviceState::getIdentifier)
+ .map(Object::toString)
+ .collect(Collectors.joining(",")));
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -141,8 +166,12 @@
pw.println(" Print this help text.");
pw.println(" state [reset|OVERRIDE_DEVICE_STATE]");
pw.println(" Return or override device state.");
+ pw.println(" print-state");
+ pw.println(" Return the current device state.");
pw.println(" print-states");
pw.println(" Return list of currently supported device states.");
+ pw.println(" print-states-simple");
+ pw.println(" Return the currently supported device states in comma separated format.");
}
private static String toString(@NonNull Optional<DeviceState> state) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9f806af..806bcc2 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,7 +16,9 @@
package com.android.server.display;
+import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
@@ -105,6 +107,34 @@
}
/**
+ * Returns the window token of the level of the WindowManager hierarchy to mirror, or null
+ * if layer mirroring by SurfaceFlinger should not be performed.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ @Nullable
+ public IBinder getWindowTokenClientToMirrorLocked() {
+ return null;
+ }
+
+ /**
+ * Updates the window token of the level of the level of the WindowManager hierarchy to mirror.
+ * If windowToken is null, then no layer mirroring by SurfaceFlinger to should be performed.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+ }
+
+ /**
+ * Returns the default size of the surface associated with the display, or null if the surface
+ * is not provided for layer mirroring by SurfaceFlinger.
+ * For now, only used for mirroring started from MediaProjection.
+ */
+ @Nullable
+ public Point getDisplaySurfaceDefaultSize() {
+ return null;
+ }
+
+ /**
* Gets the name of the display device.
*
* @return The display device name.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7d06d6e..39fd962 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -63,8 +63,6 @@
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
-import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
-import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -1749,10 +1747,13 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
+ // Mirror the part of WM hierarchy that corresponds to the provided window token.
+ IBinder windowTokenClientToMirror = device.getWindowTokenClientToMirrorLocked();
+
// Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
- if (!ownContent) {
+ if (!ownContent && windowTokenClientToMirror == null) {
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the requested logical display contents if possible.
@@ -3285,6 +3286,9 @@
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) {
+ return null;
+ }
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
if (device == null) {
return null;
@@ -3311,6 +3315,40 @@
}
return config.getRefreshRateLimitations();
}
+
+ @Override
+ public IBinder getWindowTokenClientToMirror(int displayId) {
+ final DisplayDevice device;
+ synchronized (mSyncRoot) {
+ device = getDeviceForDisplayLocked(displayId);
+ if (device == null) {
+ return null;
+ }
+ }
+ return device.getWindowTokenClientToMirrorLocked();
+ }
+
+ @Override
+ public void setWindowTokenClientToMirror(int displayId, IBinder windowToken) {
+ synchronized (mSyncRoot) {
+ final DisplayDevice device = getDeviceForDisplayLocked(displayId);
+ if (device != null) {
+ device.setWindowTokenClientToMirrorLocked(windowToken);
+ }
+ }
+ }
+
+ @Override
+ public Point getDisplaySurfaceDefaultSize(int displayId) {
+ final DisplayDevice device;
+ synchronized (mSyncRoot) {
+ device = getDeviceForDisplayLocked(displayId);
+ if (device == null) {
+ return null;
+ }
+ }
+ return device.getDisplaySurfaceDefaultSize();
+ }
}
class DesiredDisplayModeSpecsObserver
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/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index f953cc8..1769712 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -601,12 +601,6 @@
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
- if (res.getBoolean(
- com.android.internal.R.bool.config_maskMainBuiltInDisplayCutout)) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
- }
- mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
- mInfo.width, mInfo.height);
mInfo.roundedCorners = RoundedCorners.fromResources(
res, mInfo.width, mInfo.height);
} else {
@@ -620,6 +614,12 @@
}
}
+ if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
+ }
+ mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+ mInfo.uniqueId, mInfo.width, mInfo.height);
+
if (mStaticDisplayInfo.isInternal) {
mInfo.type = Display.TYPE_INTERNAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index b7931c8..34d2b01 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -31,7 +31,9 @@
import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
+import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Point;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjection;
@@ -231,6 +233,7 @@
private Display.Mode mMode;
private boolean mIsDisplayOn;
private int mDisplayIdToMirror;
+ private IBinder mWindowTokenClientToMirror;
public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
int ownerUid, String ownerPackageName, Surface surface, int flags,
@@ -253,6 +256,7 @@
mUniqueIndex = uniqueIndex;
mIsDisplayOn = surface != null;
mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
+ mWindowTokenClientToMirror = virtualDisplayConfig.getWindowTokenClientToMirror();
}
@Override
@@ -282,6 +286,26 @@
return mDisplayIdToMirror;
}
+ @Override
+ @Nullable
+ public IBinder getWindowTokenClientToMirrorLocked() {
+ return mWindowTokenClientToMirror;
+ }
+
+ @Override
+ public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+ if (mWindowTokenClientToMirror != windowToken) {
+ mWindowTokenClientToMirror = windowToken;
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+ sendTraversalRequestLocked();
+ }
+ }
+
+ @Override
+ public Point getDisplaySurfaceDefaultSize() {
+ return mSurface.getDefaultSize();
+ }
+
@VisibleForTesting
Surface getSurfaceLocked() {
return mSurface;
@@ -362,6 +386,7 @@
pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
pw.println("mStopped=" + mStopped);
pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
+ pw.println("mWindowTokenClientToMirror=" + mWindowTokenClientToMirror);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index de65d76..3509062 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -68,7 +68,6 @@
protected final HdmiControlService mService;
protected final int mDeviceType;
- protected int mAddress;
protected int mPreferredAddress;
@GuardedBy("mLock")
protected HdmiDeviceInfo mDeviceInfo;
@@ -187,7 +186,6 @@
protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) {
mService = service;
mDeviceType = deviceType;
- mAddress = Constants.ADDR_UNREGISTERED;
mLock = service.getServiceLock();
}
@@ -254,7 +252,7 @@
protected int dispatchMessage(HdmiCecMessage message) {
assertRunOnServiceThread();
int dest = message.getDestination();
- if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
+ if (dest != mDeviceInfo.getLogicalAddress() && dest != Constants.ADDR_BROADCAST) {
return Constants.NOT_HANDLED;
}
// Cache incoming message if it is included in the list of cacheable opcodes.
@@ -388,7 +386,7 @@
} else {
HdmiCecMessage cecMessage =
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- mAddress, physicalAddress, mDeviceType);
+ mDeviceInfo.getLogicalAddress(), physicalAddress, mDeviceType);
mService.sendCecCommand(cecMessage);
}
return Constants.HANDLED;
@@ -403,7 +401,8 @@
mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
} else {
HdmiCecMessage cecMessage =
- HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, vendorId);
+ HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ mDeviceInfo.getLogicalAddress(), vendorId);
mService.sendCecCommand(cecMessage);
}
return Constants.HANDLED;
@@ -476,8 +475,8 @@
protected void buildAndSendSetOsdName(int dest) {
HdmiCecMessage cecMessage =
- HdmiCecMessageBuilder.buildSetOsdNameCommand(
- mAddress, dest, mDeviceInfo.getDisplayName());
+ HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ mDeviceInfo.getLogicalAddress(), dest, mDeviceInfo.getDisplayName());
if (cecMessage != null) {
mService.sendCecCommand(cecMessage, new SendMessageCallback() {
@Override
@@ -525,7 +524,8 @@
if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals(
HdmiUtils.getDefaultDeviceName(address))) {
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address));
+ HdmiCecMessageBuilder.buildGiveOsdNameCommand(
+ mDeviceInfo.getLogicalAddress(), address));
}
return Constants.HANDLED;
@@ -630,8 +630,13 @@
List<Integer> deviceFeatures = getDeviceFeatures();
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildReportFeatures(mAddress, mService.getCecVersion(),
- localDeviceTypes, rcProfile, rcFeatures, deviceFeatures));
+ HdmiCecMessageBuilder.buildReportFeatures(
+ mDeviceInfo.getLogicalAddress(),
+ mService.getCecVersion(),
+ localDeviceTypes,
+ rcProfile,
+ rcFeatures,
+ deviceFeatures));
}
@ServiceThreadOnly
@@ -793,7 +798,9 @@
protected int handleGiveDevicePowerStatus(HdmiCecMessage message) {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportPowerStatus(
- mAddress, message.getSource(), mService.getPowerStatus()));
+ mDeviceInfo.getLogicalAddress(),
+ message.getSource(),
+ mService.getPowerStatus()));
return Constants.HANDLED;
}
@@ -802,7 +809,9 @@
// Always report menu active to receive Remote Control.
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportMenuStatus(
- mAddress, message.getSource(), Constants.MENU_STATE_ACTIVATED));
+ mDeviceInfo.getLogicalAddress(),
+ message.getSource(),
+ Constants.MENU_STATE_ACTIVATED));
return Constants.HANDLED;
}
@@ -884,7 +893,7 @@
@ServiceThreadOnly
final void handleAddressAllocated(int logicalAddress, int reason) {
assertRunOnServiceThread();
- mAddress = mPreferredAddress = logicalAddress;
+ mPreferredAddress = logicalAddress;
if (mService.getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0) {
reportFeatures();
}
@@ -914,14 +923,7 @@
@ServiceThreadOnly
boolean isAddressOf(int addr) {
assertRunOnServiceThread();
- return addr == mAddress;
- }
-
- // Resets the logical address to unregistered(15), meaning the logical device is invalid.
- @ServiceThreadOnly
- void clearAddress() {
- assertRunOnServiceThread();
- mAddress = Constants.ADDR_UNREGISTERED;
+ return addr == mDeviceInfo.getLogicalAddress();
}
@ServiceThreadOnly
@@ -1184,7 +1186,8 @@
}
List<SendKeyAction> action = getActions(SendKeyAction.class);
int logicalAddress = findKeyReceiverAddress();
- if (logicalAddress == Constants.ADDR_INVALID || logicalAddress == mAddress) {
+ if (logicalAddress == Constants.ADDR_INVALID
+ || logicalAddress == mDeviceInfo.getLogicalAddress()) {
// Don't send key event to invalid device or itself.
Slog.w(
TAG,
@@ -1222,7 +1225,8 @@
}
List<SendKeyAction> action = getActions(SendKeyAction.class);
int logicalAddress = findAudioReceiverAddress();
- if (logicalAddress == Constants.ADDR_INVALID || logicalAddress == mAddress) {
+ if (logicalAddress == Constants.ADDR_INVALID
+ || logicalAddress == mDeviceInfo.getLogicalAddress()) {
// Don't send key event to invalid device or itself.
Slog.w(
TAG,
@@ -1276,9 +1280,11 @@
void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildUserControlPressed(mAddress, targetAddress, cecKeycode));
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mDeviceInfo.getLogicalAddress(), targetAddress, cecKeycode));
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildUserControlReleased(mAddress, targetAddress));
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mDeviceInfo.getLogicalAddress(), targetAddress));
}
void addActiveSourceHistoryItem(ActiveSource activeSource, boolean isActiveSource,
@@ -1298,7 +1304,6 @@
/** Dump internal status of HdmiCecLocalDevice object. */
protected void dump(final IndentingPrintWriter pw) {
pw.println("mDeviceType: " + mDeviceType);
- pw.println("mAddress: " + mAddress);
pw.println("mPreferredAddress: " + mPreferredAddress);
pw.println("mDeviceInfo: " + mDeviceInfo);
pw.println("mActiveSource: " + getActiveSource());
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 93b0560..1fa6241 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -254,9 +254,12 @@
}
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- mAddress, mService.getPhysicalAddress(), mDeviceType));
+ getDeviceInfo().getLogicalAddress(),
+ mService.getPhysicalAddress(),
+ mDeviceType));
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, mService.getVendorId()));
+ HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ getDeviceInfo().getLogicalAddress(), mService.getVendorId()));
mService.registerTvInputCallback(mTvInputCallback);
// Some TVs, for example Mi TV, need ARC on before turning System Audio Mode on
// to request Short Audio Descriptor. Since ARC and SAM are independent,
@@ -406,7 +409,9 @@
}
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportSystemAudioMode(
- mAddress, message.getSource(), isSystemAudioModeOnOrTurningOn));
+ getDeviceInfo().getLogicalAddress(),
+ message.getSource(),
+ isSystemAudioModeOnOrTurningOn));
return Constants.HANDLED;
}
@@ -488,7 +493,7 @@
} else {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
- mAddress, message.getSource(), sadBytes));
+ getDeviceInfo().getLogicalAddress(), message.getSource(), sadBytes));
return Constants.HANDLED;
}
}
@@ -656,7 +661,9 @@
mService.sendCecCommand(
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- mAddress, Constants.ADDR_BROADCAST, systemAudioStatusOn));
+ getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ systemAudioStatusOn));
if (systemAudioStatusOn) {
// If TV sends out SAM Request with a path of a non-CEC device, which should not show
@@ -754,7 +761,7 @@
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportAudioStatus(
- mAddress, source, scaledVolume, mute));
+ getDeviceInfo().getLogicalAddress(), source, scaledVolume, mute));
}
/**
@@ -908,7 +915,8 @@
setRoutingPort(portId);
setLocalActivePort(portId);
HdmiCecMessage routingChange =
- HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+ HdmiCecMessageBuilder.buildRoutingChange(
+ getDeviceInfo().getLogicalAddress(), oldPath, newPath);
mService.sendCecCommand(routingChange);
}
@@ -933,7 +941,7 @@
// send <Set System Audio Mode> [“Off”]
mService.sendCecCommand(
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- mAddress, Constants.ADDR_BROADCAST, false));
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST, false));
}
}
@@ -981,7 +989,7 @@
setSystemAudioMode(true);
mService.sendCecCommand(
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- mAddress, Constants.ADDR_BROADCAST, true));
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST, true));
return Constants.HANDLED;
}
// Check if TV supports System Audio Control.
@@ -992,7 +1000,9 @@
setSystemAudioMode(true);
mService.sendCecCommand(
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- mAddress, Constants.ADDR_BROADCAST, true));
+ getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ true));
} else {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
}
@@ -1150,8 +1160,9 @@
return;
}
// Otherwise will switch to the current active port and broadcast routing information.
- mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingInformation(
- mAddress, routingInformationPath));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildRoutingInformation(
+ getDeviceInfo().getLogicalAddress(), routingInformationPath));
routeToInputFromPortId(getRoutingPort());
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 1276aa3..4376c9a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -75,10 +75,14 @@
getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST,
"HdmiCecLocalDevicePlayback#onAddressAllocated()");
}
- mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- mAddress, mService.getPhysicalAddress(), mDeviceType));
- mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
- mAddress, mService.getVendorId()));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ getDeviceInfo().getLogicalAddress(),
+ mService.getPhysicalAddress(),
+ mDeviceType));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ getDeviceInfo().getLogicalAddress(), mService.getVendorId()));
// Actively send out an OSD name to the TV to update the TV panel in case the TV
// does not query the OSD name on time. This is not a required behavior by the spec.
// It is used for some TVs that need the OSD name update but don't query it themselves.
@@ -87,8 +91,10 @@
// If current device is not a functional audio system device,
// send message to potential audio system device in the system to get the system
// audio mode status. If no response, set to false.
- mService.sendCecCommand(HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mAddress, Constants.ADDR_AUDIO_SYSTEM), new SendMessageCallback() {
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_AUDIO_SYSTEM),
+ new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != SendMessageResult.SUCCESS) {
@@ -144,8 +150,9 @@
return;
}
if (initiatedByCec) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(mAddress,
- mService.getPhysicalAddress()));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildInactiveSource(
+ getDeviceInfo().getLogicalAddress(), mService.getPhysicalAddress()));
return;
}
switch (standbyAction) {
@@ -157,23 +164,28 @@
switch (powerControlMode) {
case HdmiControlManager.POWER_CONTROL_MODE_TV:
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_TV));
break;
case HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM:
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_TV));
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress,
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(),
Constants.ADDR_AUDIO_SYSTEM));
break;
case HdmiControlManager.POWER_CONTROL_MODE_BROADCAST:
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress,
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(),
Constants.ADDR_BROADCAST));
break;
case HdmiControlManager.POWER_CONTROL_MODE_NONE:
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildInactiveSource(mAddress,
+ HdmiCecMessageBuilder.buildInactiveSource(
+ getDeviceInfo().getLogicalAddress(),
mService.getPhysicalAddress()));
break;
}
@@ -181,7 +193,8 @@
case HdmiControlService.STANDBY_SHUTDOWN:
// ACTION_SHUTDOWN is taken as a signal to power off all the devices.
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST));
break;
}
}
@@ -330,7 +343,7 @@
protected int handleSystemAudioModeStatus(HdmiCecMessage message) {
// Only directly addressed System Audio Mode Status message can change internal
// system audio mode status.
- if (message.getDestination() == mAddress
+ if (message.getDestination() == getDeviceInfo().getLogicalAddress()
&& message.getSource() == Constants.ADDR_AUDIO_SYSTEM) {
boolean setSystemAudioModeOn = HdmiUtils.parseCommandParamSystemAudioStatus(message);
if (mService.isSystemAudioActivated() != setSystemAudioModeOn) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 0c7b3f6..d4fa1df 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -111,13 +111,17 @@
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST)) {
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST));
return;
}
- mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_TV));
if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM)) {
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_AUDIO_SYSTEM));
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_AUDIO_SYSTEM));
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 1d099da..b087507 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -168,10 +168,14 @@
mArcFeatureEnabled.put(port.getId(), port.isArcSupported());
}
mService.registerTvInputCallback(mTvInputCallback);
- mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- mAddress, mService.getPhysicalAddress(), mDeviceType));
- mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
- mAddress, mService.getVendorId()));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ getDeviceInfo().getLogicalAddress(),
+ mService.getPhysicalAddress(),
+ mDeviceType));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ getDeviceInfo().getLogicalAddress(), mService.getVendorId()));
mService.getHdmiCecNetwork().addCecSwitch(
mService.getHdmiCecNetwork().getPhysicalAddress()); // TV is a CEC switch too.
mTvInputs.clear();
@@ -182,7 +186,9 @@
launchDeviceDiscovery();
startQueuedActions();
if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildRequestActiveSource(mAddress));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildRequestActiveSource(
+ getDeviceInfo().getLogicalAddress()));
}
}
@@ -265,15 +271,19 @@
private void handleSelectInternalSource() {
assertRunOnServiceThread();
// Seq #18
- if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
- updateActiveSource(mAddress, mService.getPhysicalAddress(),
+ if (mService.isControlEnabled()
+ && getActiveSource().logicalAddress != getDeviceInfo().getLogicalAddress()) {
+ updateActiveSource(
+ getDeviceInfo().getLogicalAddress(),
+ mService.getPhysicalAddress(),
"HdmiCecLocalDeviceTv#handleSelectInternalSource()");
if (mSkipRoutingControl) {
mSkipRoutingControl = false;
return;
}
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- mAddress, mService.getPhysicalAddress());
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ getDeviceInfo().getLogicalAddress(), mService.getPhysicalAddress());
mService.sendCecCommand(activeSource);
}
}
@@ -294,7 +304,7 @@
setActiveSource(newActive, caller);
int logicalAddress = newActive.logicalAddress;
if (mService.getHdmiCecNetwork().getCecDeviceInfo(logicalAddress) != null
- && logicalAddress != mAddress) {
+ && logicalAddress != getDeviceInfo().getLogicalAddress()) {
if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
setPrevPortId(getActivePortId());
}
@@ -383,7 +393,8 @@
return;
}
HdmiCecMessage routingChange =
- HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+ HdmiCecMessageBuilder.buildRoutingChange(
+ getDeviceInfo().getLogicalAddress(), oldPath, newPath);
mService.sendCecCommand(routingChange);
removeAction(RoutingControlAction.class);
addAndStartAction(
@@ -485,9 +496,10 @@
protected int handleRequestActiveSource(HdmiCecMessage message) {
assertRunOnServiceThread();
// Seq #19
- if (mAddress == getActiveSource().logicalAddress) {
+ if (getDeviceInfo().getLogicalAddress() == getActiveSource().logicalAddress) {
mService.sendCecCommand(
- HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath()));
+ HdmiCecMessageBuilder.buildActiveSource(
+ getDeviceInfo().getLogicalAddress(), getActivePath()));
}
return Constants.HANDLED;
}
@@ -506,8 +518,9 @@
@ServiceThreadOnly
boolean broadcastMenuLanguage(String language) {
assertRunOnServiceThread();
- HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
- mAddress, language);
+ HdmiCecMessage command =
+ HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+ getDeviceInfo().getLogicalAddress(), language);
if (command != null) {
mService.sendCecCommand(command);
return true;
@@ -1213,8 +1226,9 @@
setActivePath(activePath);
if (!routingForBootup
&& !mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(mAddress,
- activePath));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildActiveSource(
+ getDeviceInfo().getLogicalAddress(), activePath));
}
}
}
@@ -1336,8 +1350,9 @@
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
== HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED;
if (!initiatedByCec && sendStandbyOnSleep) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(
- mAddress, Constants.ADDR_BROADCAST));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), Constants.ADDR_BROADCAST));
}
}
@@ -1410,7 +1425,9 @@
// Remove one touch record action so that other one touch record can be started.
removeAction(OneTouchRecordAction.class);
- mService.sendCecCommand(HdmiCecMessageBuilder.buildRecordOff(mAddress, recorderAddress));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildRecordOff(
+ getDeviceInfo().getLogicalAddress(), recorderAddress));
Slog.i(TAG, "Stop [One Touch Record]-Target:" + recorderAddress);
}
@@ -1491,16 +1508,19 @@
HdmiCecMessage message = null;
switch (sourceType) {
case TIMER_RECORDING_TYPE_DIGITAL:
- message = HdmiCecMessageBuilder.buildClearDigitalTimer(mAddress, recorderAddress,
- recordSource);
+ message =
+ HdmiCecMessageBuilder.buildClearDigitalTimer(
+ getDeviceInfo().getLogicalAddress(), recorderAddress, recordSource);
break;
case TIMER_RECORDING_TYPE_ANALOGUE:
- message = HdmiCecMessageBuilder.buildClearAnalogueTimer(mAddress, recorderAddress,
- recordSource);
+ message =
+ HdmiCecMessageBuilder.buildClearAnalogueTimer(
+ getDeviceInfo().getLogicalAddress(), recorderAddress, recordSource);
break;
case TIMER_RECORDING_TYPE_EXTERNAL:
- message = HdmiCecMessageBuilder.buildClearExternalTimer(mAddress, recorderAddress,
- recordSource);
+ message =
+ HdmiCecMessageBuilder.buildClearExternalTimer(
+ getDeviceInfo().getLogicalAddress(), recorderAddress, recordSource);
break;
default:
Slog.w(TAG, "Invalid source type:" + recorderAddress);
@@ -1568,7 +1588,9 @@
return;
}
int targetAddress = targetDevice.getLogicalAddress();
- mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress));
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(
+ getDeviceInfo().getLogicalAddress(), targetAddress));
}
@ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 7ceaa95..225785a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -166,18 +166,6 @@
}
return false;
}
- /**
- * Clear all logical addresses registered in the device.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- */
- @ServiceThreadOnly
- void clearLogicalAddress() {
- assertRunOnServiceThread();
- for (int i = 0; i < mLocalDevices.size(); ++i) {
- mLocalDevices.valueAt(i).clearAddress();
- }
- }
@ServiceThreadOnly
void clearLocalDevices() {
@@ -862,7 +850,7 @@
private boolean isLocalDeviceAddress(int address) {
for (int i = 0; i < mLocalDevices.size(); i++) {
int key = mLocalDevices.keyAt(i);
- if (mLocalDevices.get(key).mAddress == address) {
+ if (mLocalDevices.get(key).getDeviceInfo().getLogicalAddress() == address) {
return true;
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java b/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
index c4dadaa..552ff37 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
@@ -77,8 +77,10 @@
private void sendReportPowerStatus(int powerStatus) {
for (HdmiCecLocalDevice localDevice : mHdmiControlService.getAllLocalDevices()) {
mHdmiControlService.sendCecCommand(
- HdmiCecMessageBuilder.buildReportPowerStatus(localDevice.mAddress,
- Constants.ADDR_BROADCAST, powerStatus));
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ localDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ powerStatus));
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c7d0e9e..d3aa3fa 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1239,13 +1239,11 @@
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
+ // initPortInfo at hotplug event.
+ mHdmiCecNetwork.initPortInfo();
if (connected && !isTvDevice()
&& getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
- if (isSwitchDevice()) {
- mHdmiCecNetwork.initPortInfo();
- HdmiLogger.debug("initPortInfo for switch device when onHotplug from tx.");
- }
ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
for (int type : mLocalDevices) {
HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type);
@@ -1395,8 +1393,9 @@
deviceInfo.getLogicalAddress(), deviceInfo.getPhysicalAddress(),
deviceInfo.getPortId(), deviceInfo.getDeviceType(), deviceInfo.getVendorId(),
newDisplayName, deviceInfo.getDevicePowerStatus(), deviceInfo.getCecVersion()));
- sendCecCommand(HdmiCecMessageBuilder.buildSetOsdNameCommand(
- device.mAddress, Constants.ADDR_TV, newDisplayName));
+ sendCecCommand(
+ HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ deviceInfo.getLogicalAddress(), Constants.ADDR_TV, newDisplayName));
}
}
@@ -2294,7 +2293,9 @@
}
sendCecCommand(
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- audioSystem().mAddress, Constants.ADDR_BROADCAST, true));
+ audioSystem().getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ true));
}
});
}
@@ -3200,7 +3201,6 @@
return;
}
mCecController.clearLogicalAddress();
- mHdmiCecNetwork.clearLogicalAddress();
mHdmiCecNetwork.clearLocalDevices();
}
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index 5ad7fab..adcef66 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -20,6 +20,7 @@
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.Slog;
import android.view.KeyEvent;
+
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
@@ -152,7 +153,7 @@
// audio system device is still plugged in. Framework checks if the volume key forwarding is
// successful or not every time to make sure the System Audio Mode status is still updated.
if (mTargetAddress == Constants.ADDR_AUDIO_SYSTEM
- && localDevice().mAddress != Constants.ADDR_TV) {
+ && localDevice().getDeviceInfo().getLogicalAddress() != Constants.ADDR_TV) {
sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
mTargetAddress, cecKeycodeAndParams), new SendMessageCallback() {
@Override
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 016c5ed..1461675 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -744,7 +744,7 @@
*
* @throws SecurityException when it's not...
*/
- protected final void assertCalledByPackageOwner(@NonNull String packageName) {
+ protected void assertCalledByPackageOwner(@NonNull String packageName) {
Objects.requireNonNull(packageName);
final int uid = Binder.getCallingUid();
final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index d3083ca..9755bdf 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3228,7 +3228,7 @@
* Interface for the system to handle request from InputMonitors.
*/
private final class InputMonitorHost extends IInputMonitorHost.Stub {
- private final IBinder mToken;
+ private IBinder mToken;
InputMonitorHost(IBinder token) {
mToken = token;
@@ -3236,12 +3236,23 @@
@Override
public void pilferPointers() {
+ if (mToken == null) {
+ throw new IllegalStateException(
+ "Illegal call to pilferPointers after InputMonitorHost is disposed.");
+ }
nativePilferPointers(mPtr, mToken);
}
@Override
public void dispose() {
- nativeRemoveInputChannel(mPtr, mToken);
+ // We do not remove the input monitor here by calling nativeRemoveInputChannel because
+ // it causes a race in InputDispatcher between the removal of the InputChannel through
+ // that call and the InputChannel#dispose call (which causes an FD hangup) from the
+ // client (b/189135695).
+ //
+ // NOTE: This means the client is responsible for properly closing the InputMonitor by
+ // disposing the InputChannel and all its duplicates.
+ mToken = null;
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 9d80b9c..2328dfc 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -116,8 +116,10 @@
*
* @param windowToken the window token that is now in control, or {@code null} if no client
* window is in control of the IME.
+ * @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent
+ * will end up to change later, or {@code false} otherwise.
*/
- public abstract void reportImeControl(@Nullable IBinder windowToken);
+ public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged);
/**
* Destroys the IME surface.
@@ -176,7 +178,8 @@
}
@Override
- public void reportImeControl(@Nullable IBinder windowToken) {
+ public void reportImeControl(@Nullable IBinder windowToken,
+ boolean imeParentChanged) {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index de78bec..35c0e9a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -154,11 +154,12 @@
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;
+import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
@@ -179,7 +180,6 @@
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.IInputSessionCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
-import com.android.internal.view.InputBindResult;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -4934,13 +4934,19 @@
return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
}
- private void reportImeControl(@Nullable IBinder windowToken) {
+ private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
synchronized (mMethodMap) {
if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in control,
// so we reset mCurPerceptible.
mCurPerceptible = true;
}
+ if (imeParentChanged) {
+ // Hide the IME method menu earlier when the IME surface parent will change in
+ // case seeing the dialog dismiss flickering during the next focused window
+ // starting the input connection.
+ mMenuController.hideInputMethodMenu();
+ }
}
}
@@ -4998,8 +5004,8 @@
}
@Override
- public void reportImeControl(@Nullable IBinder windowToken) {
- mService.reportImeControl(windowToken);
+ public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
+ mService.reportImeControl(windowToken, imeParentChanged);
}
@Override
@@ -5831,7 +5837,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/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java
index a4f11b2..5fa2b1c 100644
--- a/services/core/java/com/android/server/media/MediaServerUtils.java
+++ b/services/core/java/com/android/server/media/MediaServerUtils.java
@@ -18,9 +18,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioPlaybackConfiguration;
import android.os.Binder;
import java.io.PrintWriter;
@@ -32,7 +29,7 @@
/**
* Verify that caller holds {@link android.Manifest.permission#DUMP}.
*/
- static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+ public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump " + tag + " from from pid="
@@ -43,18 +40,4 @@
return true;
}
}
-
- /**
- * Whether the given stream is currently active or not.
- */
- static boolean isStreamActive(AudioManager audioManager, int stream) {
- for (AudioPlaybackConfiguration configuration
- : audioManager.getActivePlaybackConfigurations()) {
- AudioAttributes attributes = configuration.getAudioAttributes();
- if (attributes != null && attributes.getVolumeControlStream() == stream) {
- return configuration.isActive();
- }
- }
- return false;
- }
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index abcf4fb..1525cd4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,6 +24,7 @@
import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.AudioManager;
+import android.media.AudioSystem;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
@@ -515,7 +516,7 @@
public void run() {
try {
if (useSuggested) {
- if (MediaServerUtils.isStreamActive(mAudioManager, stream)) {
+ if (AudioSystem.isStreamActive(stream, 0)) {
mAudioManager.adjustSuggestedStreamVolumeForUid(stream,
direction, flags, opPackageName, uid, pid,
mContext.getApplicationInfo().targetSdkVersion);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 491cd18..87982cd 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -42,6 +42,7 @@
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
+import android.media.AudioSystem;
import android.media.IRemoteSessionCallback;
import android.media.MediaCommunicationManager;
import android.media.Session2Token;
@@ -1302,6 +1303,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 +1353,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 +1367,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 +1525,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 +1557,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 +1589,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 +1621,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();
@@ -2147,7 +2173,7 @@
boolean preferSuggestedStream = false;
if (isValidLocalStreamType(suggestedStream)
- && MediaServerUtils.isStreamActive(mAudioManager, suggestedStream)) {
+ && AudioSystem.isStreamActive(suggestedStream, 0)) {
preferSuggestedStream = true;
}
if (session == null || preferSuggestedStream) {
@@ -2156,8 +2182,7 @@
+ ". flags=" + flags + ", preferSuggestedStream="
+ preferSuggestedStream + ", session=" + session);
}
- if (musicOnly && !MediaServerUtils.isStreamActive(mAudioManager,
- AudioManager.STREAM_MUSIC)) {
+ if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
+ " flags=" + flags);
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 50eed19..c4c21df 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -325,7 +325,8 @@
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
- if (record.checkPlaybackActiveState(true)) {
+ // Do not send the volume key events to remote sessions.
+ if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) {
mCachedVolumeDefault = record;
return record;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4ee867b..097b071 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -289,8 +289,7 @@
private String mActiveIface;
/** Set of any ifaces associated with mobile networks since boot. */
- @GuardedBy("mStatsLock")
- private String[] mMobileIfaces = new String[0];
+ private volatile String[] mMobileIfaces = new String[0];
/** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
@GuardedBy("mStatsLock")
@@ -935,7 +934,12 @@
@Override
public String[] getMobileIfaces() {
- return mMobileIfaces;
+ // TODO (b/192758557): Remove debug log.
+ if (ArrayUtils.contains(mMobileIfaces, null)) {
+ throw new NullPointerException(
+ "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+ }
+ return mMobileIfaces.clone();
}
@Override
@@ -1084,7 +1088,8 @@
}
@Override
- public long getIfaceStats(String iface, int type) {
+ public long getIfaceStats(@NonNull String iface, int type) {
+ Objects.requireNonNull(iface);
long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
if (nativeIfaceStats == -1) {
return nativeIfaceStats;
@@ -1382,7 +1387,12 @@
}
}
- mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
+ mMobileIfaces = mobileIfaces.toArray(new String[0]);
+ // TODO (b/192758557): Remove debug log.
+ if (ArrayUtils.contains(mMobileIfaces, null)) {
+ throw new NullPointerException(
+ "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+ }
}
private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
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/CommitRequest.java b/services/core/java/com/android/server/pm/CommitRequest.java
new file mode 100644
index 0000000..d1a6002
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CommitRequest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+
+import java.util.Map;
+
+/**
+ * Package state to commit to memory and disk after reconciliation has completed.
+ */
+final class CommitRequest {
+ final Map<String, ReconciledPackage> mReconciledPackages;
+ @NonNull final int[] mAllUsers;
+
+ CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
+ @NonNull int[] allUsers) {
+ mReconciledPackages = reconciledPackages;
+ mAllUsers = allUsers;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DeletePackageAction.java b/services/core/java/com/android/server/pm/DeletePackageAction.java
new file mode 100644
index 0000000..8ef6601
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DeletePackageAction.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.UserHandle;
+
+final class DeletePackageAction {
+ public final PackageSetting mDeletingPs;
+ public final PackageSetting mDisabledPs;
+ public final PackageRemovedInfo mRemovedInfo;
+ public final int mFlags;
+ public final UserHandle mUser;
+
+ DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
+ PackageRemovedInfo removedInfo, int flags, UserHandle user) {
+ mDeletingPs = deletingPs;
+ mDisabledPs = disabledPs;
+ mRemovedInfo = removedInfo;
+ mFlags = flags;
+ mUser = user;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java
new file mode 100644
index 0000000..3e18374
--- /dev/null
+++ b/services/core/java/com/android/server/pm/FileInstallArgs.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.content.pm.PackageManager.INSTALL_STAGED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
+
+import android.content.pm.DataLoaderType;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.SELinux;
+import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logic to handle installation of new applications, including copying
+ * and renaming logic.
+ */
+class FileInstallArgs extends InstallArgs {
+ private File mCodeFile;
+
+ // Example topology:
+ // /data/app/com.example/base.apk
+ // /data/app/com.example/split_foo.apk
+ // /data/app/com.example/lib/arm/libfoo.so
+ // /data/app/com.example/lib/arm64/libfoo.so
+ // /data/app/com.example/dalvik/arm/base.apk@classes.dex
+
+ /** New install */
+ FileInstallArgs(InstallParams params) {
+ super(params);
+ }
+
+ /** Existing install */
+ FileInstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
+ super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
+ null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
+ SigningDetails.UNKNOWN,
+ PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
+ false, DataLoaderType.NONE, pm);
+ mCodeFile = (codePath != null) ? new File(codePath) : null;
+ }
+
+ int copyApk() {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
+ try {
+ return doCopyApk();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ private int doCopyApk() {
+ if (mOriginInfo.mStaged) {
+ if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
+ mCodeFile = mOriginInfo.mFile;
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ try {
+ final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ final File tempDir =
+ mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
+ mCodeFile = tempDir;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to create copy file: " + e);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+
+ int ret = PackageManagerServiceUtils.copyPackage(
+ mOriginInfo.mFile.getAbsolutePath(), mCodeFile);
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Failed to copy package");
+ return ret;
+ }
+
+ final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
+ final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
+ NativeLibraryHelper.Handle handle = null;
+ try {
+ handle = NativeLibraryHelper.Handle.create(mCodeFile);
+ ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
+ mAbiOverride, isIncremental);
+ } catch (IOException e) {
+ Slog.e(TAG, "Copying native libraries failed", e);
+ ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
+
+ return ret;
+ }
+
+ int doPreInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ @Override
+ boolean doRename(int status, ParsedPackage parsedPackage) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ return false;
+ }
+
+ final File targetDir = resolveTargetDir();
+ final File beforeCodeFile = mCodeFile;
+ final File afterCodeFile = PackageManagerService.getNextCodePath(targetDir,
+ parsedPackage.getPackageName());
+
+ if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+ final boolean onIncremental = mPm.mIncrementalManager != null
+ && isIncrementalPath(beforeCodeFile.getAbsolutePath());
+ try {
+ makeDirRecursive(afterCodeFile.getParentFile(), 0775);
+ if (onIncremental) {
+ // Just link files here. The stage dir will be removed when the installation
+ // session is completed.
+ mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
+ } else {
+ Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+ }
+ } catch (IOException | ErrnoException e) {
+ Slog.w(TAG, "Failed to rename", e);
+ return false;
+ }
+
+ if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
+ Slog.w(TAG, "Failed to restorecon");
+ return false;
+ }
+
+ // Reflect the rename internally
+ mCodeFile = afterCodeFile;
+
+ // Reflect the rename in scanned details
+ try {
+ parsedPackage.setPath(afterCodeFile.getCanonicalPath());
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
+ return false;
+ }
+ parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
+ afterCodeFile, parsedPackage.getBaseApkPath()));
+ parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
+ afterCodeFile, parsedPackage.getSplitCodePaths()));
+
+ return true;
+ }
+
+ // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
+ // flow, we won't need this method anymore.
+ private File resolveTargetDir() {
+ boolean isStagedInstall = (mInstallFlags & INSTALL_STAGED) != 0;
+ if (isStagedInstall) {
+ return Environment.getDataAppDirectory(null);
+ } else {
+ return mCodeFile.getParentFile();
+ }
+ }
+
+ int doPostInstall(int status, int uid) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ @Override
+ String getCodePath() {
+ return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
+ }
+
+ private boolean cleanUp() {
+ if (mCodeFile == null || !mCodeFile.exists()) {
+ return false;
+ }
+ mPm.removeCodePathLI(mCodeFile);
+ return true;
+ }
+
+ void cleanUpResourcesLI() {
+ // Try enumerating all code paths before deleting
+ List<String> allCodePaths = Collections.EMPTY_LIST;
+ if (mCodeFile != null && mCodeFile.exists()) {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ input.reset(), mCodeFile, /* flags */ 0);
+ if (result.isSuccess()) {
+ // Ignore error; we tried our best
+ allCodePaths = result.getResult().getAllApkPaths();
+ }
+ }
+
+ cleanUp();
+ removeDexFiles(allCodePaths, mInstructionSets);
+ }
+
+ void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+ if (!allCodePaths.isEmpty()) {
+ if (instructionSets == null) {
+ throw new IllegalStateException("instructionSet == null");
+ }
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String codePath : allCodePaths) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ try {
+ mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet);
+ } catch (Installer.InstallerException ignored) {
+ }
+ }
+ }
+ }
+ }
+
+ boolean doPostDeleteLI(boolean delete) {
+ // XXX err, shouldn't we respect the delete flag?
+ cleanUpResourcesLI();
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java
new file mode 100644
index 0000000..b8c2eb8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/HandlerParams.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.server.pm;
+
+import android.os.UserHandle;
+import android.util.Slog;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+abstract class HandlerParams {
+ /** User handle for the user requesting the information or installation. */
+ private final UserHandle mUser;
+ String mTraceMethod;
+ int mTraceCookie;
+
+ HandlerParams(UserHandle user) {
+ mUser = user;
+ }
+
+ UserHandle getUser() {
+ return mUser;
+ }
+
+ HandlerParams setTraceMethod(String traceMethod) {
+ mTraceMethod = traceMethod;
+ return this;
+ }
+
+ HandlerParams setTraceCookie(int traceCookie) {
+ mTraceCookie = traceCookie;
+ return this;
+ }
+
+ final void startCopy() {
+ if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
+ handleStartCopy();
+ handleReturnCode();
+ }
+
+ abstract void handleStartCopy();
+ abstract void handleReturnCode();
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
new file mode 100644
index 0000000..bb797cb
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.IPackageLoadingProgressCallback;
+
+/**
+ * Loading progress callback, used to listen for progress changes and update package setting
+ */
+final class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
+ private final String mPackageName;
+ private final PackageManagerService mPm;
+ IncrementalProgressListener(String packageName, PackageManagerService pm) {
+ mPackageName = packageName;
+ mPm = pm;
+ }
+
+ @Override
+ public void onPackageLoadingProgressChanged(float progress) {
+ final PackageSetting ps;
+ synchronized (mPm.mLock) {
+ ps = mPm.mSettings.getPackageLPr(mPackageName);
+ if (ps == null) {
+ return;
+ }
+ ps.setLoadingProgress(progress);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index 7627281..3101ca7 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -118,12 +118,19 @@
* @param progress Value between [0, 1].
*/
public void setProgress(float progress) {
+ final boolean oldLoadingState;
final boolean newLoadingState;
synchronized (mLock) {
- updateProgressLocked(progress);
+ oldLoadingState = mLoadingState.isLoading();
+ if (oldLoadingState) {
+ // Due to asynchronous progress reporting, incomplete progress might be received
+ // after the app is migrated off incremental. Ignore such progress updates.
+ updateProgressLocked(progress);
+ }
newLoadingState = mLoadingState.isLoading();
}
- if (!newLoadingState) {
+ if (oldLoadingState && !newLoadingState) {
+ // Only report the state change when loading state changes from true to false
onLoadingStateChanged();
}
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStatesCallback.java b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java
new file mode 100644
index 0000000..478c99b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+/**
+ * Package states callback, used to listen for package state changes and send broadcasts
+ */
+final class IncrementalStatesCallback implements IncrementalStates.Callback {
+ private final String mPackageName;
+ private final PackageManagerService mPm;
+
+ IncrementalStatesCallback(String packageName, PackageManagerService pm) {
+ mPackageName = packageName;
+ mPm = pm;
+ }
+
+ @Override
+ public void onPackageFullyLoaded() {
+ final String codePath;
+ synchronized (mPm.mLock) {
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(mPackageName);
+ if (ps == null) {
+ return;
+ }
+ codePath = ps.getPathString();
+ }
+ // Unregister progress listener
+ mPm.mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
+ // Make sure the information is preserved
+ mPm.scheduleWriteSettingsLocked();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
new file mode 100644
index 0000000..07c7123
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.util.List;
+
+abstract class InstallArgs {
+ /** @see InstallParams#mOriginInfo */
+ final OriginInfo mOriginInfo;
+ /** @see InstallParams#mMoveInfo */
+ final MoveInfo mMoveInfo;
+
+ final IPackageInstallObserver2 mObserver;
+ // Always refers to PackageManager flags only
+ final int mInstallFlags;
+ @NonNull
+ final InstallSource mInstallSource;
+ final String mVolumeUuid;
+ final UserHandle mUser;
+ final String mAbiOverride;
+ final String[] mInstallGrantPermissions;
+ final List<String> mAllowlistedRestrictedPermissions;
+ final int mAutoRevokePermissionsMode;
+ /** If non-null, drop an async trace when the install completes */
+ final String mTraceMethod;
+ final int mTraceCookie;
+ final SigningDetails mSigningDetails;
+ final int mInstallReason;
+ final int mInstallScenario;
+ final boolean mForceQueryableOverride;
+ final int mDataLoaderType;
+
+ // The list of instruction sets supported by this app. This is currently
+ // only used during the rmdex() phase to clean up resources. We can get rid of this
+ // if we move dex files under the common app path.
+ @Nullable String[] mInstructionSets;
+
+ @NonNull final PackageManagerService mPm;
+
+ InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
+ int installFlags, InstallSource installSource, String volumeUuid,
+ UserHandle user, String[] instructionSets,
+ String abiOverride, String[] installGrantPermissions,
+ List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode,
+ String traceMethod, int traceCookie, SigningDetails signingDetails,
+ int installReason, int installScenario, boolean forceQueryableOverride,
+ int dataLoaderType, PackageManagerService pm) {
+ mOriginInfo = originInfo;
+ mMoveInfo = moveInfo;
+ mInstallFlags = installFlags;
+ mObserver = observer;
+ mInstallSource = Preconditions.checkNotNull(installSource);
+ mVolumeUuid = volumeUuid;
+ mUser = user;
+ mInstructionSets = instructionSets;
+ mAbiOverride = abiOverride;
+ mInstallGrantPermissions = installGrantPermissions;
+ mAllowlistedRestrictedPermissions = allowlistedRestrictedPermissions;
+ mAutoRevokePermissionsMode = autoRevokePermissionsMode;
+ mTraceMethod = traceMethod;
+ mTraceCookie = traceCookie;
+ mSigningDetails = signingDetails;
+ mInstallReason = installReason;
+ mInstallScenario = installScenario;
+ mForceQueryableOverride = forceQueryableOverride;
+ mDataLoaderType = dataLoaderType;
+ mPm = pm;
+ }
+
+ /** New install */
+ InstallArgs(InstallParams params) {
+ this(params.mOriginInfo, params.mMoveInfo, params.mObserver, params.mInstallFlags,
+ params.mInstallSource, params.mVolumeUuid,
+ params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
+ params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
+ params.mAutoRevokePermissionsMode,
+ params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
+ params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
+ params.mDataLoaderType, params.mPm);
+ }
+
+ abstract int copyApk();
+ abstract int doPreInstall(int status);
+
+ /**
+ * Rename package into final resting place. All paths on the given
+ * scanned package should be updated to reflect the rename.
+ */
+ abstract boolean doRename(int status, ParsedPackage parsedPackage);
+ abstract int doPostInstall(int status, int uid);
+
+ /** @see PackageSettingBase#getPath() */
+ abstract String getCodePath();
+
+ // Need installer lock especially for dex file removal.
+ abstract void cleanUpResourcesLI();
+ abstract boolean doPostDeleteLI(boolean delete);
+
+ /**
+ * Called before the source arguments are copied. This is used mostly
+ * for MoveParams when it needs to read the source file to put it in the
+ * destination.
+ */
+ int doPreCopy() {
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ /**
+ * Called after the source arguments are copied. This is used mostly for
+ * MoveParams when it needs to read the source file to put it in the
+ * destination.
+ */
+ int doPostCopy(int uid) {
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ protected boolean isEphemeral() {
+ return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ }
+
+ UserHandle getUser() {
+ return mUser;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
new file mode 100644
index 0000000..e87dbed
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -0,0 +1,2159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
+import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
+import static android.content.pm.PackageManager.INSTALL_STAGED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT;
+import static com.android.server.pm.PackageManagerService.INIT_COPY;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.PRECOMPILE_LAYOUTS;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD;
+import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
+import static com.android.server.pm.PackageManagerService.SCAN_MOVE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
+import static com.android.server.pm.PackageManagerService.SCAN_UPDATE_SIGNATURE;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
+import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ApplicationPackageManager;
+import android.content.pm.DataLoaderType;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageChangeEvent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.F2fsUtils;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.security.VerityUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.Watchdog;
+import com.android.server.pm.dex.DexoptOptions;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.Permission;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+final class InstallParams extends HandlerParams {
+ final OriginInfo mOriginInfo;
+ final MoveInfo mMoveInfo;
+ final IPackageInstallObserver2 mObserver;
+ int mInstallFlags;
+ @NonNull
+ final InstallSource mInstallSource;
+ final String mVolumeUuid;
+ int mRet;
+ final String mPackageAbiOverride;
+ final String[] mGrantedRuntimePermissions;
+ final List<String> mAllowlistedRestrictedPermissions;
+ final int mAutoRevokePermissionsMode;
+ final SigningDetails mSigningDetails;
+ final int mInstallReason;
+ final int mInstallScenario;
+ @Nullable
+ MultiPackageInstallParams mParentInstallParams;
+ final boolean mForceQueryableOverride;
+ final int mDataLoaderType;
+ final long mRequiredInstalledVersionCode;
+ final PackageLite mPackageLite;
+ @NonNull final PackageManagerService mPm;
+
+ InstallParams(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
+ int installFlags, InstallSource installSource, String volumeUuid,
+ UserHandle user, String packageAbiOverride, PackageLite packageLite,
+ PackageManagerService pm) {
+ super(user);
+ mPm = pm;
+ mOriginInfo = originInfo;
+ mMoveInfo = moveInfo;
+ mObserver = observer;
+ mInstallFlags = installFlags;
+ mInstallSource = Preconditions.checkNotNull(installSource);
+ mVolumeUuid = volumeUuid;
+ mPackageAbiOverride = packageAbiOverride;
+
+ mGrantedRuntimePermissions = null;
+ mAllowlistedRestrictedPermissions = null;
+ mAutoRevokePermissionsMode = MODE_DEFAULT;
+ mSigningDetails = SigningDetails.UNKNOWN;
+ mInstallReason = PackageManager.INSTALL_REASON_UNKNOWN;
+ mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
+ mForceQueryableOverride = false;
+ mDataLoaderType = DataLoaderType.NONE;
+ mRequiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
+ mPackageLite = packageLite;
+ }
+
+ InstallParams(File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ UserHandle user, SigningDetails signingDetails, int installerUid,
+ PackageLite packageLite, PackageManagerService pm) {
+ super(user);
+ mPm = pm;
+ mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
+ mMoveInfo = null;
+ mInstallReason = fixUpInstallReason(
+ installSource.installerPackageName, installerUid, sessionParams.installReason);
+ mInstallScenario = sessionParams.installScenario;
+ mObserver = observer;
+ mInstallFlags = sessionParams.installFlags;
+ mInstallSource = installSource;
+ mVolumeUuid = sessionParams.volumeUuid;
+ mPackageAbiOverride = sessionParams.abiOverride;
+ mGrantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
+ mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
+ mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
+ mSigningDetails = signingDetails;
+ mForceQueryableOverride = sessionParams.forceQueryableOverride;
+ mDataLoaderType = (sessionParams.dataLoaderParams != null)
+ ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+ mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ mPackageLite = packageLite;
+ }
+
+ @Override
+ public String toString() {
+ return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+ + " file=" + mOriginInfo.mFile + "}";
+ }
+
+ private int installLocationPolicy(PackageInfoLite pkgLite) {
+ String packageName = pkgLite.packageName;
+ int installLocation = pkgLite.installLocation;
+ // reader
+ synchronized (mPm.mLock) {
+ // Currently installed package which the new package is attempting to replace or
+ // null if no such package is installed.
+ AndroidPackage installedPkg = mPm.mPackages.get(packageName);
+
+ if (installedPkg != null) {
+ if ((mInstallFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ // Check for updated system application.
+ if (installedPkg.isSystem()) {
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ } else {
+ // If current upgrade specifies particular preference
+ if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ // Application explicitly specified internal.
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ } else if (
+ installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+ // App explicitly prefers external. Let policy decide
+ } else {
+ // Prefer previous location
+ if (installedPkg.isExternalStorage()) {
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ }
+ }
+ } else {
+ // Invalid install. Return error code
+ return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
+ }
+ }
+ }
+ return pkgLite.recommendedInstallLocation;
+ }
+
+ /**
+ * Override install location based on default policy if needed.
+ *
+ * Only {@link #mInstallFlags} may mutate in this method.
+ *
+ * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in
+ * {@link #mInstallFlags}
+ */
+ private int overrideInstallLocation(PackageInfoLite pkgLite) {
+ final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ if (DEBUG_INSTANT && ephemeral) {
+ Slog.v(TAG, "pkgLite for install: " + pkgLite);
+ }
+
+ if (mOriginInfo.mStaged) {
+ // If we're already staged, we've firmly committed to an install location
+ if (mOriginInfo.mFile != null) {
+ mInstallFlags |= PackageManager.INSTALL_INTERNAL;
+ } else {
+ throw new IllegalStateException("Invalid stage location");
+ }
+ } else if (pkgLite.recommendedInstallLocation
+ == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+ /*
+ * If we are not staged and have too little free space, try to free cache
+ * before giving up.
+ */
+ // TODO: focus freeing disk space on the target device
+ final StorageManager storage = StorageManager.from(mPm.mContext);
+ final long lowThreshold = storage.getStorageLowBytes(
+ Environment.getDataDirectory());
+
+ final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
+ mOriginInfo.mResolvedPath, mPackageAbiOverride);
+ if (sizeBytes >= 0) {
+ try {
+ mPm.mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
+ pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+ mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags,
+ mPackageAbiOverride);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, "Failed to free cache", e);
+ }
+ }
+
+ /*
+ * The cache free must have deleted the file we downloaded to install.
+ *
+ * TODO: fix the "freeCache" call to not delete the file we care about.
+ */
+ if (pkgLite.recommendedInstallLocation
+ == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+ pkgLite.recommendedInstallLocation =
+ PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ int ret = INSTALL_SUCCEEDED;
+ int loc = pkgLite.recommendedInstallLocation;
+ if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
+ ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+ ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_URI;
+ } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
+ ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+ } else {
+ // Override with defaults if needed.
+ loc = installLocationPolicy(pkgLite);
+
+ final boolean onInt = (mInstallFlags & PackageManager.INSTALL_INTERNAL) != 0;
+
+ if (!onInt) {
+ // Override install location with flags
+ if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+ // Set the flag to install on external media.
+ mInstallFlags &= ~PackageManager.INSTALL_INTERNAL;
+ } else {
+ // Make sure the flag for installing on external
+ // media is unset
+ mInstallFlags |= PackageManager.INSTALL_INTERNAL;
+ }
+ }
+ }
+ return ret;
+ }
+
+ /*
+ * Invoke remote method to get package information and install
+ * location values. Override install location based on default
+ * policy if needed and then create install arguments based
+ * on the install location.
+ */
+ public void handleStartCopy() {
+ if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
+ mRet = INSTALL_SUCCEEDED;
+ return;
+ }
+ PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+ mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
+
+ // For staged session, there is a delay between its verification and install. Device
+ // state can change within this delay and hence we need to re-verify certain conditions.
+ boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
+ if (isStaged) {
+ Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+ pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
+ mRet = ret.first;
+ if (mRet != INSTALL_SUCCEEDED) {
+ return;
+ }
+ }
+
+ mRet = overrideInstallLocation(pkgLite);
+ }
+
+ @Override
+ void handleReturnCode() {
+ processPendingInstall();
+ }
+
+ private void processPendingInstall() {
+ InstallArgs args = createInstallArgs(this);
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ mRet = args.copyApk();
+ }
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ F2fsUtils.releaseCompressedBlocks(
+ mPm.mContext.getContentResolver(), new File(args.getCodePath()));
+ }
+ if (mParentInstallParams != null) {
+ mParentInstallParams.tryProcessInstallRequest(args, mRet);
+ } else {
+ PackageInstalledInfo res = new PackageInstalledInfo(mRet);
+ processInstallRequestsAsync(
+ res.mReturnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+ }
+ }
+
+ private InstallArgs createInstallArgs(InstallParams params) {
+ if (params.mMoveInfo != null) {
+ return new MoveInstallArgs(params);
+ } else {
+ return new FileInstallArgs(params);
+ }
+ }
+
+ // Queue up an async operation since the package installation may take a little while.
+ private void processInstallRequestsAsync(boolean success,
+ List<InstallRequest> installRequests) {
+ mPm.mHandler.post(() -> {
+ List<InstallRequest> apexInstallRequests = new ArrayList<>();
+ List<InstallRequest> apkInstallRequests = new ArrayList<>();
+ for (InstallRequest request : installRequests) {
+ if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
+ apexInstallRequests.add(request);
+ } else {
+ apkInstallRequests.add(request);
+ }
+ }
+ // Note: supporting multi package install of both APEXes and APKs might requir some
+ // thinking to ensure atomicity of the install.
+ if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
+ // This should've been caught at the validation step, but for some reason wasn't.
+ throw new IllegalStateException(
+ "Attempted to do a multi package install of both APEXes and APKs");
+ }
+ if (!apexInstallRequests.isEmpty()) {
+ if (success) {
+ // Since installApexPackages requires talking to external service (apexd), we
+ // schedule to run it async. Once it finishes, it will resume the install.
+ Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
+ "installApexPackages");
+ t.start();
+ } else {
+ // Non-staged APEX installation failed somewhere before
+ // processInstallRequestAsync. In that case just notify the observer about the
+ // failure.
+ InstallRequest request = apexInstallRequests.get(0);
+ mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
+ }
+ return;
+ }
+ if (success) {
+ for (InstallRequest request : apkInstallRequests) {
+ request.mArgs.doPreInstall(request.mInstallResult.mReturnCode);
+ }
+ synchronized (mPm.mInstallLock) {
+ installPackagesTracedLI(apkInstallRequests);
+ }
+ for (InstallRequest request : apkInstallRequests) {
+ request.mArgs.doPostInstall(
+ request.mInstallResult.mReturnCode, request.mInstallResult.mUid);
+ }
+ }
+ for (InstallRequest request : apkInstallRequests) {
+ mPm.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
+ request.mInstallResult,
+ new PackageManagerService.PostInstallData(request.mArgs,
+ request.mInstallResult, null));
+ }
+ });
+ }
+
+ private void installApexPackagesTraced(List<InstallRequest> requests) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages");
+ installApexPackages(requests);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ private void installApexPackages(List<InstallRequest> requests) {
+ if (requests.isEmpty()) {
+ return;
+ }
+ if (requests.size() != 1) {
+ throw new IllegalStateException(
+ "Only a non-staged install of a single APEX is supported");
+ }
+ InstallRequest request = requests.get(0);
+ try {
+ // Should directory scanning logic be moved to ApexManager for better test coverage?
+ final File dir = request.mArgs.mOriginInfo.mResolvedFile;
+ final File[] apexes = dir.listFiles();
+ if (apexes == null) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ dir.getAbsolutePath() + " is not a directory");
+ }
+ if (apexes.length != 1) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Expected exactly one .apex file under " + dir.getAbsolutePath()
+ + " got: " + apexes.length);
+ }
+ try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
+ mPm.mApexManager.installPackage(apexes[0], packageParser);
+ }
+ } catch (PackageManagerException e) {
+ request.mInstallResult.setError("APEX installation failed", e);
+ }
+ PackageManagerService.invalidatePackageInfoCache();
+ mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
+ }
+
+ @GuardedBy("mInstallLock")
+ private void installPackagesTracedLI(List<InstallRequest> requests) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+ installPackagesLI(requests);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Installs one or more packages atomically. This operation is broken up into four phases:
+ * <ul>
+ * <li><b>Prepare</b>
+ * <br/>Analyzes any current install state, parses the package and does initial
+ * validation on it.</li>
+ * <li><b>Scan</b>
+ * <br/>Interrogates the parsed packages given the context collected in prepare.</li>
+ * <li><b>Reconcile</b>
+ * <br/>Validates scanned packages in the context of each other and the current system
+ * state to ensure that the install will be successful.
+ * <li><b>Commit</b>
+ * <br/>Commits all scanned packages and updates system state. This is the only place
+ * that system state may be modified in the install flow and all predictable errors
+ * must be determined before this phase.</li>
+ * </ul>
+ *
+ * Failure at any phase will result in a full failure to install all packages.
+ */
+ @GuardedBy("mInstallLock")
+ private void installPackagesLI(List<InstallRequest> requests) {
+ final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
+ final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
+ final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
+ final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
+ final Map<String, Settings.VersionInfo> versionInfos = new ArrayMap<>(requests.size());
+ final Map<String, PackageSetting> lastStaticSharedLibSettings =
+ new ArrayMap<>(requests.size());
+ final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
+ boolean success = false;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
+ for (InstallRequest request : requests) {
+ // TODO(b/109941548): remove this once we've pulled everything from it and into
+ // scan, reconcile or commit.
+ final PrepareResult prepareResult;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
+ prepareResult =
+ preparePackageLI(request.mArgs, request.mInstallResult);
+ } catch (PrepareFailure prepareFailure) {
+ request.mInstallResult.setError(prepareFailure.error,
+ prepareFailure.getMessage());
+ request.mInstallResult.mOrigPackage = prepareFailure.mConflictingPackage;
+ request.mInstallResult.mOrigPermission = prepareFailure.mConflictingPermission;
+ return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ request.mInstallResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ request.mInstallResult.mInstallerPackageName =
+ request.mArgs.mInstallSource.installerPackageName;
+
+ final String packageName = prepareResult.mPackageToScan.getPackageName();
+ prepareResults.put(packageName, prepareResult);
+ installResults.put(packageName, request.mInstallResult);
+ installArgs.put(packageName, request.mArgs);
+ try {
+ final ScanResult result = mPm.scanPackageTracedLI(
+ prepareResult.mPackageToScan, prepareResult.mParseFlags,
+ prepareResult.mScanFlags, System.currentTimeMillis(),
+ request.mArgs.mUser, request.mArgs.mAbiOverride);
+ if (null != preparedScans.put(result.mPkgSetting.pkg.getPackageName(),
+ result)) {
+ request.mInstallResult.setError(
+ PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Duplicate package " + result.mPkgSetting.pkg.getPackageName()
+ + " in multi-package install request.");
+ return;
+ }
+ createdAppId.put(packageName, mPm.optimisticallyRegisterAppId(result));
+ versionInfos.put(result.mPkgSetting.pkg.getPackageName(),
+ mPm.getSettingsVersionForPackage(result.mPkgSetting.pkg));
+ if (result.mStaticSharedLibraryInfo != null) {
+ final PackageSetting sharedLibLatestVersionSetting =
+ mPm.getSharedLibLatestVersionSetting(result);
+ if (sharedLibLatestVersionSetting != null) {
+ lastStaticSharedLibSettings.put(result.mPkgSetting.pkg.getPackageName(),
+ sharedLibLatestVersionSetting);
+ }
+ }
+ } catch (PackageManagerException e) {
+ request.mInstallResult.setError("Scanning Failed.", e);
+ return;
+ }
+ }
+ ReconcileRequest
+ reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
+ installResults,
+ prepareResults,
+ mPm.mSharedLibraries,
+ Collections.unmodifiableMap(mPm.mPackages), versionInfos,
+ lastStaticSharedLibSettings);
+ CommitRequest commitRequest = null;
+ synchronized (mPm.mLock) {
+ Map<String, ReconciledPackage> reconciledPackages;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
+ reconciledPackages = PackageManagerService.reconcilePackagesLocked(
+ reconcileRequest, mPm.mSettings.getKeySetManagerService(),
+ mPm.mInjector);
+ } catch (ReconcileFailure e) {
+ for (InstallRequest request : requests) {
+ request.mInstallResult.setError("Reconciliation failed...", e);
+ }
+ return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
+ commitRequest = new CommitRequest(reconciledPackages,
+ mPm.mUserManager.getUserIds());
+ commitPackagesLocked(commitRequest);
+ success = true;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+ executePostCommitSteps(commitRequest);
+ } finally {
+ if (success) {
+ for (InstallRequest request : requests) {
+ final InstallArgs args = request.mArgs;
+ if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
+ continue;
+ }
+ if (args.mSigningDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
+ continue;
+ }
+ // For incremental installs, we bypass the verifier prior to install. Now
+ // that we know the package is valid, send a notice to the verifier with
+ // the root hash of the base.apk.
+ final String baseCodePath = request.mInstallResult.mPkg.getBaseApkPath();
+ final String[] splitCodePaths = request.mInstallResult.mPkg.getSplitCodePaths();
+ final Uri originUri = Uri.fromFile(args.mOriginInfo.mResolvedFile);
+ final int verificationId = mPm.mPendingVerificationToken++;
+ final String rootHashString = PackageManagerServiceUtils
+ .buildVerificationRootHashString(baseCodePath, splitCodePaths);
+ mPm.broadcastPackageVerified(verificationId, originUri,
+ PackageManager.VERIFICATION_ALLOW, rootHashString,
+ args.mDataLoaderType, args.getUser());
+ }
+ } else {
+ for (ScanResult result : preparedScans.values()) {
+ if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(),
+ false)) {
+ mPm.cleanUpAppIdCreation(result);
+ }
+ }
+ // TODO(b/194319951): create a more descriptive reason than unknown
+ // mark all non-failure installs as UNKNOWN so we do not treat them as success
+ for (InstallRequest request : requests) {
+ if (request.mInstallResult.mFreezer != null) {
+ request.mInstallResult.mFreezer.close();
+ }
+ if (request.mInstallResult.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
+ request.mInstallResult.mReturnCode = PackageManager.INSTALL_UNKNOWN;
+ }
+ }
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ @GuardedBy("mInstallLock")
+ private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
+ throws PrepareFailure {
+ final int installFlags = args.mInstallFlags;
+ final File tmpPackageFile = new File(args.getCodePath());
+ final boolean onExternal = args.mVolumeUuid != null;
+ final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
+ final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
+ final boolean virtualPreload =
+ ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
+ final boolean isRollback = args.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
+ @PackageManagerService.ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
+ if (args.mMoveInfo != null) {
+ // moving a complete application; perform an initial scan on the new install location
+ scanFlags |= SCAN_INITIAL;
+ }
+ if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ scanFlags |= SCAN_DONT_KILL_APP;
+ }
+ if (instantApp) {
+ scanFlags |= SCAN_AS_INSTANT_APP;
+ }
+ if (fullApp) {
+ scanFlags |= SCAN_AS_FULL_APP;
+ }
+ if (virtualPreload) {
+ scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
+ }
+
+ if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
+
+ // Validity check
+ if (instantApp && onExternal) {
+ Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID);
+ }
+
+ // Retrieve PackageSettings and parse package
+ @ParsingPackageUtils.ParseFlags final int parseFlags =
+ mPm.mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
+ | ParsingPackageUtils.PARSE_ENFORCE_CODE
+ | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
+ final ParsedPackage parsedPackage;
+ try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
+ parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+ AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+ } catch (PackageManagerException e) {
+ throw new PrepareFailure("Failed parse during installPackageLI", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Instant apps have several additional install-time checks.
+ if (instantApp) {
+ if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ + " does not target at least O");
+ throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+ "Instant app package must target at least O");
+ }
+ if (parsedPackage.getSharedUserId() != null) {
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ + " may not declare sharedUserId.");
+ throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+ "Instant app package may not declare a sharedUserId");
+ }
+ }
+
+ if (parsedPackage.isStaticSharedLibrary()) {
+ // Static shared libraries have synthetic package names
+ PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
+
+ // No static shared libs on external storage
+ if (onExternal) {
+ Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ "Packages declaring static-shared libs cannot be updated");
+ }
+ }
+
+ String pkgName = res.mName = parsedPackage.getPackageName();
+ if (parsedPackage.isTestOnly()) {
+ if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
+ throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
+ }
+ }
+
+ // either use what we've been given or parse directly from the APK
+ if (args.mSigningDetails != SigningDetails.UNKNOWN) {
+ parsedPackage.setSigningDetails(args.mSigningDetails);
+ } 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());
+ }
+ parsedPackage.setSigningDetails(result.getResult());
+ }
+
+ if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
+ < SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+ + " is not signed with at least APK Signature Scheme v2");
+ throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+ "Instant app package must be signed with APK Signature Scheme v2 or greater");
+ }
+
+ boolean systemApp = false;
+ boolean replace = false;
+ synchronized (mPm.mLock) {
+ // Check if installing already existing package
+ if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ String oldName = mPm.mSettings.getRenamedPackageLPr(pkgName);
+ if (parsedPackage.getOriginalPackages().contains(oldName)
+ && mPm.mPackages.containsKey(oldName)) {
+ // This package is derived from an original package,
+ // and this device has been updating from that original
+ // name. We must continue using the original name, so
+ // rename the new package here.
+ parsedPackage.setPackageName(oldName);
+ pkgName = parsedPackage.getPackageName();
+ replace = true;
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "Replacing existing renamed package: oldName="
+ + oldName + " pkgName=" + pkgName);
+ }
+ } else if (mPm.mPackages.containsKey(pkgName)) {
+ // This package, under its official name, already exists
+ // on the device; we should replace it.
+ replace = true;
+ if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing package: " + pkgName);
+ }
+
+ if (replace) {
+ // Prevent apps opting out from runtime permissions
+ AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
+ final int oldTargetSdk = oldPackage.getTargetSdkVersion();
+ final int newTargetSdk = parsedPackage.getTargetSdkVersion();
+ if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
+ && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+ "Package " + parsedPackage.getPackageName()
+ + " new target SDK " + newTargetSdk
+ + " doesn't support runtime permissions but the old"
+ + " target SDK " + oldTargetSdk + " does.");
+ }
+ // Prevent persistent apps from being updated
+ if (oldPackage.isPersistent()
+ && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
+ "Package " + oldPackage.getPackageName() + " is a persistent app. "
+ + "Persistent apps are not updateable.");
+ }
+ }
+ }
+
+ PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+ if (ps != null) {
+ if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
+
+ // Static shared libs have same package with different versions where
+ // we internally use a synthetic package name to allow multiple versions
+ // of the same package, therefore we need to compare signatures against
+ // the package setting for the latest library version.
+ PackageSetting signatureCheckPs = ps;
+ if (parsedPackage.isStaticSharedLibrary()) {
+ SharedLibraryInfo libraryInfo = mPm.getLatestSharedLibraVersionLPr(
+ parsedPackage);
+ if (libraryInfo != null) {
+ signatureCheckPs = mPm.mSettings.getPackageLPr(
+ libraryInfo.getPackageName());
+ }
+ }
+
+ // Quick validity check that we're signed correctly if updating;
+ // we'll check this again later when scanning, but we want to
+ // bail early here before tripping over redefined permissions.
+ final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ + parsedPackage.getPackageName() + " upgrade keys do not match the "
+ + "previously installed version");
+ }
+ } else {
+ try {
+ final boolean compareCompat = mPm.isCompatSignatureUpdateNeeded(
+ parsedPackage);
+ final boolean compareRecover = mPm.isRecoverSignatureUpdateNeeded(
+ parsedPackage);
+ // We don't care about disabledPkgSetting on install for now.
+ final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+ parsedPackage.getSigningDetails(), compareCompat, compareRecover,
+ isRollback);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPm.mLock) {
+ ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
+ }
+ }
+ } catch (PackageManagerException e) {
+ throw new PrepareFailure(e.error, e.getMessage());
+ }
+ }
+
+ if (ps.pkg != null) {
+ systemApp = ps.pkg.isSystem();
+ }
+ res.mOrigUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
+ }
+
+ final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
+ for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+ final ParsedPermissionGroup group =
+ parsedPackage.getPermissionGroups().get(groupNum);
+ final PermissionGroupInfo sourceGroup = mPm.getPermissionGroupInfo(group.getName(),
+ 0);
+
+ if (sourceGroup != null && cannotInstallWithBadPermissionGroups(parsedPackage)) {
+ final String sourcePackageName = sourceGroup.packageName;
+
+ if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName))
+ && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
+ scanFlags)) {
+ EventLog.writeEvent(0x534e4554, "146211400", -1,
+ parsedPackage.getPackageName());
+
+ throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP,
+ "Package "
+ + parsedPackage.getPackageName()
+ + " attempting to redeclare permission group "
+ + group.getName() + " already owned by "
+ + sourcePackageName);
+ }
+ }
+ }
+
+ // TODO: Move logic for checking permission compatibility into PermissionManagerService
+ final int n = ArrayUtils.size(parsedPackage.getPermissions());
+ for (int i = n - 1; i >= 0; i--) {
+ final ParsedPermission perm = parsedPackage.getPermissions().get(i);
+ final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName());
+
+ // Don't allow anyone but the system to define ephemeral permissions.
+ if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+ && !systemApp) {
+ Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
+ + " attempting to delcare ephemeral permission "
+ + perm.getName() + "; Removing ephemeral.");
+ perm.setProtectionLevel(
+ perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
+ }
+
+ // Check whether the newly-scanned package wants to define an already-defined perm
+ if (bp != null) {
+ final String sourcePackageName = bp.getPackageName();
+
+ if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
+ scanFlags)) {
+ // If the owning package is the system itself, we log but allow
+ // install to proceed; we fail the install on all other permission
+ // redefinitions.
+ if (!sourcePackageName.equals("android")) {
+ throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION,
+ "Package "
+ + parsedPackage.getPackageName()
+ + " attempting to redeclare permission "
+ + perm.getName() + " already owned by "
+ + sourcePackageName)
+ .conflictsWithExistingPermission(perm.getName(),
+ sourcePackageName);
+ } else {
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ + " attempting to redeclare system permission "
+ + perm.getName() + "; ignoring new declaration");
+ parsedPackage.removePermission(i);
+ }
+ } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
+ // Prevent apps to change protection level to dangerous from any other
+ // type as this would allow a privilege escalation where an app adds a
+ // normal/signature permission in other app's group and later redefines
+ // it as dangerous leading to the group auto-grant.
+ if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_DANGEROUS) {
+ if (bp != null && !bp.isRuntime()) {
+ Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ + " trying to change a non-runtime permission "
+ + perm.getName()
+ + " to runtime; keeping old protection level");
+ perm.setProtectionLevel(bp.getProtectionLevel());
+ }
+ }
+ }
+ }
+
+ if (perm.getGroup() != null
+ && cannotInstallWithBadPermissionGroups(parsedPackage)) {
+ boolean isPermGroupDefinedByPackage = false;
+ for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+ if (parsedPackage.getPermissionGroups().get(groupNum).getName()
+ .equals(perm.getGroup())) {
+ isPermGroupDefinedByPackage = true;
+ break;
+ }
+ }
+
+ if (!isPermGroupDefinedByPackage) {
+ final PermissionGroupInfo sourceGroup =
+ mPm.getPermissionGroupInfo(perm.getGroup(), 0);
+
+ if (sourceGroup == null) {
+ EventLog.writeEvent(0x534e4554, "146211400", -1,
+ parsedPackage.getPackageName());
+
+ throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
+ "Package "
+ + parsedPackage.getPackageName()
+ + " attempting to declare permission "
+ + perm.getName() + " in non-existing group "
+ + perm.getGroup());
+ } else {
+ String groupSourcePackageName = sourceGroup.packageName;
+
+ if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName)
+ && !doesSignatureMatchForPermissions(groupSourcePackageName,
+ parsedPackage, scanFlags)) {
+ EventLog.writeEvent(0x534e4554, "146211400", -1,
+ parsedPackage.getPackageName());
+
+ throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
+ "Package "
+ + parsedPackage.getPackageName()
+ + " attempting to declare permission "
+ + perm.getName() + " in group "
+ + perm.getGroup() + " owned by package "
+ + groupSourcePackageName
+ + " with incompatible certificate");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (systemApp) {
+ if (onExternal) {
+ // Abort update; system app can't be replaced with app on sdcard
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ "Cannot install updates to system apps on sdcard");
+ } else if (instantApp) {
+ // Abort update; system app can't be replaced with an instant app
+ throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+ "Cannot update a system app with an instant app");
+ }
+ }
+
+ if (args.mMoveInfo != null) {
+ // We did an in-place move, so dex is ready to roll
+ scanFlags |= SCAN_NO_DEX;
+ scanFlags |= SCAN_MOVE;
+
+ synchronized (mPm.mLock) {
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+ if (ps == null) {
+ res.setError(INSTALL_FAILED_INTERNAL_ERROR,
+ "Missing settings for moved package " + pkgName);
+ }
+
+ // We moved the entire application as-is, so bring over the
+ // previously derived ABI information.
+ parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
+ .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
+ }
+
+ } else {
+ // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
+ scanFlags |= SCAN_NO_DEX;
+
+ try {
+ PackageSetting pkgSetting;
+ synchronized (mPm.mLock) {
+ pkgSetting = mPm.mSettings.getPackageLPr(pkgName);
+ }
+ boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
+ && pkgSetting.getPkgState().isUpdatedSystemApp();
+ final String abiOverride = deriveAbiOverride(args.mAbiOverride);
+ AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
+ boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
+ final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+ derivedAbi = mPm.mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
+ isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
+ abiOverride, mPm.mAppLib32InstallDir);
+ derivedAbi.first.applyTo(parsedPackage);
+ derivedAbi.second.applyTo(parsedPackage);
+ } catch (PackageManagerException pme) {
+ Slog.e(TAG, "Error deriving application ABI", pme);
+ throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+ "Error deriving application ABI: " + pme.getMessage());
+ }
+ }
+
+ if (!args.doRename(res.mReturnCode, parsedPackage)) {
+ throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
+ }
+
+ try {
+ setUpFsVerityIfPossible(parsedPackage);
+ } catch (Installer.InstallerException | IOException | DigestException
+ | NoSuchAlgorithmException e) {
+ throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to set up verity: " + e);
+ }
+
+ final PackageFreezer freezer =
+ freezePackageForInstall(pkgName, installFlags, "installPackageLI");
+ boolean shouldCloseFreezerBeforeReturn = true;
+ try {
+ final AndroidPackage existingPackage;
+ String renamedPackage = null;
+ boolean sysPkg = false;
+ int targetScanFlags = scanFlags;
+ int targetParseFlags = parseFlags;
+ final PackageSetting ps;
+ final PackageSetting disabledPs;
+ if (replace) {
+ if (parsedPackage.isStaticSharedLibrary()) {
+ // Static libs have a synthetic package name containing the version
+ // and cannot be updated as an update would get a new package name,
+ // unless this is installed from adb which is useful for development.
+ AndroidPackage existingPkg = mPm.mPackages.get(parsedPackage.getPackageName());
+ if (existingPkg != null
+ && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) {
+ throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Packages declaring "
+ + "static-shared libs cannot be updated");
+ }
+ }
+
+ final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+
+ final AndroidPackage oldPackage;
+ final String pkgName11 = parsedPackage.getPackageName();
+ final int[] allUsers;
+ final int[] installedUsers;
+ final int[] uninstalledUsers;
+
+ synchronized (mPm.mLock) {
+ oldPackage = mPm.mPackages.get(pkgName11);
+ existingPackage = oldPackage;
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG,
+ "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
+ }
+
+ ps = mPm.mSettings.getPackageLPr(pkgName11);
+ disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps);
+
+ // verify signatures are valid
+ final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+ if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "New package not signed by keys specified by upgrade-keysets: "
+ + pkgName11);
+ }
+ } else {
+ SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
+ SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
+ // default to original signature matching
+ if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
+ SigningDetails.CertCapabilities.INSTALLED_DATA)
+ && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
+ SigningDetails.CertCapabilities.ROLLBACK)) {
+ // Allow the update to proceed if this is a rollback and the parsed
+ // package's current signing key is the current signer or in the lineage
+ // of the old package; this allows a rollback to a previously installed
+ // version after an app's signing key has been rotated without requiring
+ // the rollback capability on the previous signing key.
+ if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
+ parsedPkgSigningDetails)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "New package has a different signature: " + pkgName11);
+ }
+ }
+ }
+
+ // don't allow a system upgrade unless the upgrade hash matches
+ if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
+ final byte[] digestBytes;
+ try {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+ updateDigest(digest, new File(parsedPackage.getBaseApkPath()));
+ if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
+ for (String path : parsedPackage.getSplitCodePaths()) {
+ updateDigest(digest, new File(path));
+ }
+ }
+ digestBytes = digest.digest();
+ } catch (NoSuchAlgorithmException | IOException e) {
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+ "Could not compute hash: " + pkgName11);
+ }
+ if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+ "New package fails restrict-update check: " + pkgName11);
+ }
+ // retain upgrade restriction
+ parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
+ }
+
+ // Check for shared user id changes
+ String invalidPackageName = null;
+ if (!Objects.equals(oldPackage.getSharedUserId(),
+ parsedPackage.getSharedUserId())) {
+ invalidPackageName = parsedPackage.getPackageName();
+ }
+
+ if (invalidPackageName != null) {
+ throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + invalidPackageName + " tried to change user "
+ + oldPackage.getSharedUserId());
+ }
+
+ // In case of rollback, remember per-user/profile install state
+ allUsers = mPm.mUserManager.getUserIds();
+ installedUsers = ps.queryInstalledUsers(allUsers, true);
+ uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
+
+
+ // don't allow an upgrade from full to ephemeral
+ if (isInstantApp) {
+ if (args.mUser == null
+ || args.mUser.getIdentifier() == UserHandle.USER_ALL) {
+ for (int currentUser : allUsers) {
+ if (!ps.getInstantApp(currentUser)) {
+ // can't downgrade from full to instant
+ Slog.w(TAG,
+ "Can't replace full app with instant app: " + pkgName11
+ + " for user: " + currentUser);
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID);
+ }
+ }
+ } else if (!ps.getInstantApp(args.mUser.getIdentifier())) {
+ // can't downgrade from full to instant
+ Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
+ + " for user: " + args.mUser.getIdentifier());
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID);
+ }
+ }
+ }
+
+ // Update what is removed
+ res.mRemovedInfo = new PackageRemovedInfo(mPm);
+ res.mRemovedInfo.mUid = oldPackage.getUid();
+ res.mRemovedInfo.mRemovedPackage = oldPackage.getPackageName();
+ res.mRemovedInfo.mInstallerPackageName = ps.installSource.installerPackageName;
+ res.mRemovedInfo.mIsStaticSharedLib =
+ parsedPackage.getStaticSharedLibName() != null;
+ res.mRemovedInfo.mIsUpdate = true;
+ res.mRemovedInfo.mOrigUsers = installedUsers;
+ res.mRemovedInfo.mInstallReasons = new SparseArray<>(installedUsers.length);
+ for (int i = 0; i < installedUsers.length; i++) {
+ final int userId = installedUsers[i];
+ res.mRemovedInfo.mInstallReasons.put(userId, ps.getInstallReason(userId));
+ }
+ res.mRemovedInfo.mUninstallReasons = new SparseArray<>(uninstalledUsers.length);
+ for (int i = 0; i < uninstalledUsers.length; i++) {
+ final int userId = uninstalledUsers[i];
+ res.mRemovedInfo.mUninstallReasons.put(userId, ps.getUninstallReason(userId));
+ }
+
+ sysPkg = oldPackage.isSystem();
+ if (sysPkg) {
+ // Set the system/privileged/oem/vendor/product flags as needed
+ final boolean privileged = oldPackage.isPrivileged();
+ final boolean oem = oldPackage.isOem();
+ final boolean vendor = oldPackage.isVendor();
+ final boolean product = oldPackage.isProduct();
+ final boolean odm = oldPackage.isOdm();
+ final boolean systemExt = oldPackage.isSystemExt();
+ final @ParsingPackageUtils.ParseFlags int systemParseFlags = parseFlags;
+ final @PackageManagerService.ScanFlags int systemScanFlags = scanFlags
+ | SCAN_AS_SYSTEM
+ | (privileged ? SCAN_AS_PRIVILEGED : 0)
+ | (oem ? SCAN_AS_OEM : 0)
+ | (vendor ? SCAN_AS_VENDOR : 0)
+ | (product ? SCAN_AS_PRODUCT : 0)
+ | (odm ? SCAN_AS_ODM : 0)
+ | (systemExt ? SCAN_AS_SYSTEM_EXT : 0);
+
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
+ + ", old=" + oldPackage);
+ }
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ targetParseFlags = systemParseFlags;
+ targetScanFlags = systemScanFlags;
+ } else { // non system replace
+ replace = true;
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG,
+ "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
+ + oldPackage);
+ }
+ }
+ } else { // new package install
+ ps = null;
+ disabledPs = null;
+ replace = false;
+ existingPackage = null;
+ // Remember this for later, in case we need to rollback this install
+ String pkgName1 = parsedPackage.getPackageName();
+
+ if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
+
+ // TODO(b/194319951): MOVE TO RECONCILE
+ synchronized (mPm.mLock) {
+ renamedPackage = mPm.mSettings.getRenamedPackageLPr(pkgName1);
+ if (renamedPackage != null) {
+ // A package with the same name is already installed, though
+ // it has been renamed to an older name. The package we
+ // are trying to install should be installed as an update to
+ // the existing one, but that has not been requested, so bail.
+ throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+ "Attempt to re-install " + pkgName1
+ + " without first uninstalling package running as "
+ + renamedPackage);
+ }
+ if (mPm.mPackages.containsKey(pkgName1)) {
+ // Don't allow installation over an existing package with the same name.
+ throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+ "Attempt to re-install " + pkgName1
+ + " without first uninstalling.");
+ }
+ }
+ }
+ // we're passing the freezer back to be closed in a later phase of install
+ shouldCloseFreezerBeforeReturn = false;
+
+ return new PrepareResult(replace, targetScanFlags, targetParseFlags,
+ existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
+ ps, disabledPs);
+ } finally {
+ res.mFreezer = freezer;
+ if (shouldCloseFreezerBeforeReturn) {
+ freezer.close();
+ }
+ }
+ }
+
+ /*
+ * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges
+ * as this only works for packages that are installed
+ *
+ * TODO: Move logic for permission group compatibility into PermissionManagerService
+ */
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) {
+ return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S;
+ }
+
+ private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
+ @NonNull ParsedPackage parsedPackage, int scanFlags) {
+ // If the defining package is signed with our cert, it's okay. This
+ // also includes the "updating the same package" case, of course.
+ // "updating same package" could also involve key-rotation.
+
+ final PackageSetting sourcePackageSetting;
+ synchronized (mPm.mLock) {
+ sourcePackageSetting = mPm.mSettings.getPackageLPr(sourcePackageName);
+ }
+
+ final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
+ ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
+ final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+ if (sourcePackageName.equals(parsedPackage.getPackageName())
+ && (ksms.shouldCheckUpgradeKeySetLocked(
+ sourcePackageSetting, scanFlags))) {
+ return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
+ } else {
+
+ // in the event of signing certificate rotation, we need to see if the
+ // package's certificate has rotated from the current one, or if it is an
+ // older certificate with which the current is ok with sharing permissions
+ if (sourceSigningDetails.checkCapability(
+ parsedPackage.getSigningDetails(),
+ SigningDetails.CertCapabilities.PERMISSION)) {
+ return true;
+ } else if (parsedPackage.getSigningDetails().checkCapability(
+ sourceSigningDetails,
+ SigningDetails.CertCapabilities.PERMISSION)) {
+ // the scanned package checks out, has signing certificate rotation
+ // history, and is newer; bring it over
+ synchronized (mPm.mLock) {
+ sourcePackageSetting.signatures.mSigningDetails =
+ parsedPackage.getSigningDetails();
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Set up fs-verity for the given package if possible. This requires a feature flag of system
+ * property to be enabled only if the kernel supports fs-verity.
+ *
+ * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
+ * kernel patches). In normal mode, all file format can be supported.
+ */
+ private void setUpFsVerityIfPossible(AndroidPackage pkg) throws Installer.InstallerException,
+ PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
+ final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+ final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+ if (!standardMode && !legacyMode) {
+ return;
+ }
+
+ if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion()
+ < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) {
+ return;
+ }
+
+ // Collect files we care for fs-verity setup.
+ ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
+ if (legacyMode) {
+ synchronized (mPm.mLock) {
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ if (ps != null && ps.isPrivileged()) {
+ fsverityCandidates.put(pkg.getBaseApkPath(), null);
+ if (pkg.getSplitCodePaths() != null) {
+ for (String splitPath : pkg.getSplitCodePaths()) {
+ fsverityCandidates.put(splitPath, null);
+ }
+ }
+ }
+ }
+ } else {
+ // NB: These files will become only accessible if the signing key is loaded in kernel's
+ // .fs-verity keyring.
+ fsverityCandidates.put(pkg.getBaseApkPath(),
+ VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath()));
+
+ final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
+ pkg.getBaseApkPath());
+ if (new File(dmPath).exists()) {
+ fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
+ }
+
+ if (pkg.getSplitCodePaths() != null) {
+ for (String path : pkg.getSplitCodePaths()) {
+ fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
+
+ final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
+ if (new File(splitDmPath).exists()) {
+ fsverityCandidates.put(splitDmPath,
+ VerityUtils.getFsveritySignatureFilePath(splitDmPath));
+ }
+ }
+ }
+ }
+
+ for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
+ final String filePath = entry.getKey();
+ final String signaturePath = entry.getValue();
+
+ if (!legacyMode) {
+ // fs-verity is optional for now. Only set up if signature is provided.
+ if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
+ try {
+ VerityUtils.setUpFsverity(filePath, signaturePath);
+ } catch (IOException e) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to enable fs-verity: " + e);
+ }
+ }
+ continue;
+ }
+
+ // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+ final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
+ if (result.isOk()) {
+ if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
+ final FileDescriptor fd = result.getUnownedFileDescriptor();
+ try {
+ final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+ try {
+ // A file may already have fs-verity, e.g. when reused during a split
+ // install. If the measurement succeeds, no need to attempt to set up.
+ mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+ } catch (Installer.InstallerException e) {
+ mPm.mInstaller.installApkVerity(filePath, fd, result.getContentSize());
+ mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+ }
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else if (result.isFailed()) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to generate verity");
+ }
+ }
+ }
+
+ private PackageFreezer freezePackageForInstall(String packageName, int installFlags,
+ String killReason) {
+ return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
+ }
+
+ private PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
+ String killReason) {
+ if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ return new PackageFreezer(mPm);
+ } else {
+ return mPm.freezePackage(packageName, userId, killReason);
+ }
+ }
+
+ private static void updateDigest(MessageDigest digest, File file) throws IOException {
+ try (DigestInputStream digestStream =
+ new DigestInputStream(new FileInputStream(file), digest)) {
+ int length, total = 0;
+ while ((length = digestStream.read()) != -1) {
+ total += length;
+ } // just plow through the file
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitPackagesLocked(final CommitRequest request) {
+ // TODO: remove any expected failures from this method; this should only be able to fail due
+ // to unavoidable errors (I/O, etc.)
+ for (ReconciledPackage reconciledPkg : request.mReconciledPackages.values()) {
+ final ScanResult scanResult = reconciledPkg.mScanResult;
+ final ScanRequest scanRequest = scanResult.mRequest;
+ final ParsedPackage parsedPackage = scanRequest.mParsedPackage;
+ final String packageName = parsedPackage.getPackageName();
+ final PackageInstalledInfo res = reconciledPkg.mInstallResult;
+
+ if (reconciledPkg.mPrepareResult.mReplace) {
+ AndroidPackage oldPackage = mPm.mPackages.get(packageName);
+
+ // Set the update and install times
+ PackageSetting deletedPkgSetting = mPm.getPackageSetting(
+ oldPackage.getPackageName());
+ reconciledPkg.mPkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
+ reconciledPkg.mPkgSetting.lastUpdateTime = System.currentTimeMillis();
+
+ res.mRemovedInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
+ reconciledPkg.mPkgSetting, request.mAllUsers,
+ mPm.mSettings.getPackagesLocked());
+ if (reconciledPkg.mPrepareResult.mSystem) {
+ // Remove existing system package
+ mPm.removePackageLI(oldPackage, true);
+ if (!disableSystemPackageLPw(oldPackage)) {
+ // We didn't need to disable the .apk as a current system package,
+ // which means we are replacing another update that is already
+ // installed. We need to make sure to delete the older one's .apk.
+ res.mRemovedInfo.mArgs = mPm.createInstallArgsForExisting(
+ oldPackage.getPath(),
+ getAppDexInstructionSets(
+ AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
+ deletedPkgSetting),
+ AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
+ deletedPkgSetting)));
+ } else {
+ res.mRemovedInfo.mArgs = null;
+ }
+ } else {
+ try {
+ // Settings will be written during the call to updateSettingsLI().
+ mPm.executeDeletePackageLIF(reconciledPkg.mDeletePackageAction, packageName,
+ true, request.mAllUsers, false);
+ } catch (SystemDeleteException e) {
+ if (mPm.mIsEngBuild) {
+ throw new RuntimeException("Unexpected failure", e);
+ // ignore; not possible for non-system app
+ }
+ }
+ // Successfully deleted the old package; proceed with replace.
+
+ // If deleted package lived in a container, give users a chance to
+ // relinquish resources before killing.
+ if (oldPackage.isExternalStorage()) {
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + oldPackage
+ + " is ASEC-hosted -> UNAVAILABLE");
+ }
+ final int[] uidArray = new int[]{oldPackage.getUid()};
+ final ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(oldPackage.getPackageName());
+ mPm.sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+ }
+
+ // Update the in-memory copy of the previous code paths.
+ PackageSetting ps1 = mPm.mSettings.getPackageLPr(
+ reconciledPkg.mPrepareResult.mExistingPackage.getPackageName());
+ if ((reconciledPkg.mInstallArgs.mInstallFlags & PackageManager.DONT_KILL_APP)
+ == 0) {
+ if (ps1.mOldCodePaths == null) {
+ ps1.mOldCodePaths = new ArraySet<>();
+ }
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());
+ if (oldPackage.getSplitCodePaths() != null) {
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
+ }
+ } else {
+ ps1.mOldCodePaths = null;
+ }
+
+ if (reconciledPkg.mInstallResult.mReturnCode
+ == PackageManager.INSTALL_SUCCEEDED) {
+ PackageSetting ps2 = mPm.mSettings.getPackageLPr(
+ parsedPackage.getPackageName());
+ if (ps2 != null) {
+ res.mRemovedInfo.mRemovedForAllUsers =
+ mPm.mPackages.get(ps2.name) == null;
+ }
+ }
+ }
+ }
+
+ AndroidPackage pkg = mPm.commitReconciledScanResultLocked(reconciledPkg,
+ request.mAllUsers);
+ updateSettingsLI(pkg, reconciledPkg.mInstallArgs, request.mAllUsers, res);
+
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+ if (ps != null) {
+ res.mNewUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
+ ps.setUpdateAvailable(false /*updateAvailable*/);
+ }
+ if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
+ mPm.updateSequenceNumberLP(ps, res.mNewUsers);
+ mPm.updateInstantAppInstallerLocked(packageName);
+ }
+ }
+ ApplicationPackageManager.invalidateGetPackagesForUidCache();
+ }
+
+ @GuardedBy("mLock")
+ private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
+ return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
+ }
+
+ private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
+ int[] allUsers, PackageInstalledInfo res) {
+ updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
+ }
+
+ private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
+ int[] allUsers, PackageInstalledInfo res) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
+
+ final String pkgName = pkg.getPackageName();
+ final int[] installedForUsers = res.mOrigUsers;
+ final int installReason = installArgs.mInstallReason;
+ InstallSource installSource = installArgs.mInstallSource;
+ final String installerPackageName = installSource.installerPackageName;
+
+ if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
+ synchronized (mPm.mLock) {
+ // For system-bundled packages, we assume that installing an upgraded version
+ // of the package implies that the user actually wants to run that new code,
+ // so we enable the package.
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+ final int userId = installArgs.mUser.getIdentifier();
+ if (ps != null) {
+ if (pkg.isSystem()) {
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
+ }
+ // Enable system package for requested users
+ if (res.mOrigUsers != null) {
+ for (int origUserId : res.mOrigUsers) {
+ if (userId == UserHandle.USER_ALL || userId == origUserId) {
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+ origUserId, installerPackageName);
+ }
+ }
+ }
+ // Also convey the prior install/uninstall state
+ if (allUsers != null && installedForUsers != null) {
+ for (int currentUserId : allUsers) {
+ final boolean installed = ArrayUtils.contains(
+ installedForUsers, currentUserId);
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, " user " + currentUserId + " => " + installed);
+ }
+ ps.setInstalled(installed, currentUserId);
+ }
+ // these install state changes will be persisted in the
+ // upcoming call to mSettings.writeLPr().
+ }
+
+ if (allUsers != null) {
+ for (int currentUserId : allUsers) {
+ ps.resetOverrideComponentLabelIcon(currentUserId);
+ }
+ }
+ }
+
+ // Retrieve the overlays for shared libraries of the package.
+ if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
+ for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
+ for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
+ if (!sharedLib.isDynamic()) {
+ // TODO(146804378): Support overlaying static shared libraries
+ continue;
+ }
+ final PackageSetting libPs = mPm.mSettings.getPackageLPr(
+ sharedLib.getPackageName());
+ if (libPs == null) {
+ continue;
+ }
+ ps.setOverlayPathsForLibrary(sharedLib.getName(),
+ libPs.getOverlayPaths(currentUserId), currentUserId);
+ }
+ }
+ }
+
+ // It's implied that when a user requests installation, they want the app to be
+ // installed and enabled. (This does not apply to USER_ALL, which here means only
+ // install on users for which the app is already installed).
+ if (userId != UserHandle.USER_ALL) {
+ ps.setInstalled(true, userId);
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+ }
+
+ mPm.mSettings.addInstallerPackageNames(ps.installSource);
+
+ // When replacing an existing package, preserve the original install reason for all
+ // users that had the package installed before. Similarly for uninstall reasons.
+ final Set<Integer> previousUserIds = new ArraySet<>();
+ if (res.mRemovedInfo != null && res.mRemovedInfo.mInstallReasons != null) {
+ final int installReasonCount = res.mRemovedInfo.mInstallReasons.size();
+ for (int i = 0; i < installReasonCount; i++) {
+ final int previousUserId = res.mRemovedInfo.mInstallReasons.keyAt(i);
+ final int previousInstallReason =
+ res.mRemovedInfo.mInstallReasons.valueAt(i);
+ ps.setInstallReason(previousInstallReason, previousUserId);
+ previousUserIds.add(previousUserId);
+ }
+ }
+ if (res.mRemovedInfo != null && res.mRemovedInfo.mUninstallReasons != null) {
+ for (int i = 0; i < res.mRemovedInfo.mUninstallReasons.size(); i++) {
+ final int previousUserId = res.mRemovedInfo.mUninstallReasons.keyAt(i);
+ final int previousReason = res.mRemovedInfo.mUninstallReasons.valueAt(i);
+ ps.setUninstallReason(previousReason, previousUserId);
+ }
+ }
+
+ // Set install reason for users that are having the package newly installed.
+ final int[] allUsersList = mPm.mUserManager.getUserIds();
+ if (userId == UserHandle.USER_ALL) {
+ // TODO(b/152629990): It appears that the package doesn't actually get newly
+ // installed in this case, so the installReason shouldn't get modified?
+ for (int currentUserId : allUsersList) {
+ if (!previousUserIds.contains(currentUserId)) {
+ ps.setInstallReason(installReason, currentUserId);
+ }
+ }
+ } else if (!previousUserIds.contains(userId)) {
+ ps.setInstallReason(installReason, userId);
+ }
+
+ // TODO(b/169721400): generalize Incremental States and create a Callback object
+ // that can be used for all the packages.
+ final String codePath = ps.getPathString();
+ if (IncrementalManager.isIncrementalPath(codePath)
+ && mPm.mIncrementalManager != null) {
+ final IncrementalStatesCallback incrementalStatesCallback =
+ new IncrementalStatesCallback(ps.name, mPm);
+ ps.setIncrementalStatesCallback(incrementalStatesCallback);
+ mPm.mIncrementalManager.registerLoadingProgressCallback(codePath,
+ new IncrementalProgressListener(ps.name, mPm));
+ }
+
+ // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
+ for (int currentUserId : allUsersList) {
+ if (ps.getInstalled(currentUserId)) {
+ ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
+ }
+ }
+
+ mPm.mSettings.writeKernelMappingLPr(ps);
+
+ final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+ permissionParamsBuilder =
+ new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
+ final boolean grantPermissions = (installArgs.mInstallFlags
+ & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+ if (grantPermissions) {
+ final List<String> grantedPermissions =
+ installArgs.mInstallGrantPermissions != null
+ ? Arrays.asList(installArgs.mInstallGrantPermissions)
+ : pkg.getRequestedPermissions();
+ permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
+ }
+ final boolean allowlistAllRestrictedPermissions =
+ (installArgs.mInstallFlags
+ & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
+ final List<String> allowlistedRestrictedPermissions =
+ allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
+ : installArgs.mAllowlistedRestrictedPermissions;
+ if (allowlistedRestrictedPermissions != null) {
+ permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+ allowlistedRestrictedPermissions);
+ }
+ final int autoRevokePermissionsMode = installArgs.mAutoRevokePermissionsMode;
+ permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
+ mPm.mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
+ userId);
+ }
+ res.mName = pkgName;
+ res.mUid = pkg.getUid();
+ res.mPkg = pkg;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ //to update install status
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
+ mPm.writeSettingsLPrTEMP();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ /**
+ * On successful install, executes remaining steps after commit completes and the package lock
+ * is released. These are typically more expensive or require calls to installd, which often
+ * locks on {@link com.android.server.pm.PackageManagerService.mLock}.
+ */
+ private void executePostCommitSteps(CommitRequest commitRequest) {
+ final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
+ for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) {
+ final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags
+ & SCAN_AS_INSTANT_APP) != 0);
+ final AndroidPackage pkg = reconciledPkg.mPkgSetting.pkg;
+ final String packageName = pkg.getPackageName();
+ final String codePath = pkg.getPath();
+ final boolean onIncremental = mPm.mIncrementalManager != null
+ && isIncrementalPath(codePath);
+ if (onIncremental) {
+ IncrementalStorage storage = mPm.mIncrementalManager.openStorage(codePath);
+ if (storage == null) {
+ throw new IllegalArgumentException(
+ "Install: null storage for incremental package " + packageName);
+ }
+ incrementalStorages.add(storage);
+ }
+ mPm.prepareAppDataAfterInstallLIF(pkg);
+ if (reconciledPkg.mPrepareResult.mClearCodeCache) {
+ mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ }
+ if (reconciledPkg.mPrepareResult.mReplace) {
+ mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
+ pkg.getBaseApkPath(), pkg.getSplitCodePaths());
+ }
+
+ // Prepare the application profiles for the new code paths.
+ // This needs to be done before invoking dexopt so that any install-time profile
+ // can be used for optimizations.
+ mPm.mArtManagerService.prepareAppProfiles(
+ pkg,
+ mPm.resolveUserIds(reconciledPkg.mInstallArgs.mUser.getIdentifier()),
+ /* updateReferenceProfileContent= */ true);
+
+ // Compute the compilation reason from the installation scenario.
+ final int compilationReason =
+ mPm.getDexManager().getCompilationReasonForInstallScenario(
+ reconciledPkg.mInstallArgs.mInstallScenario);
+
+ // Construct the DexoptOptions early to see if we should skip running dexopt.
+ //
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ final boolean isBackupOrRestore =
+ reconciledPkg.mInstallArgs.mInstallReason == INSTALL_REASON_DEVICE_RESTORE
+ || reconciledPkg.mInstallArgs.mInstallReason
+ == INSTALL_REASON_DEVICE_SETUP;
+
+ final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
+ | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
+ | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);
+ DexoptOptions dexoptOptions =
+ new DexoptOptions(packageName, compilationReason, dexoptFlags);
+
+ // Check whether we need to dexopt the app.
+ //
+ // NOTE: it is IMPORTANT to call dexopt:
+ // - after doRename which will sync the package data from AndroidPackage and
+ // its corresponding ApplicationInfo.
+ // - after installNewPackageLIF or replacePackageLIF which will update result with the
+ // uid of the application (pkg.applicationInfo.uid).
+ // This update happens in place!
+ //
+ // We only need to dexopt if the package meets ALL of the following conditions:
+ // 1) it is not an instant app or if it is then dexopt is enabled via gservices.
+ // 2) it is not debuggable.
+ // 3) it is not on Incremental File System.
+ //
+ // Note that we do not dexopt instant apps by default. dexopt can take some time to
+ // complete, so we skip this step during installation. Instead, we'll take extra time
+ // the first time the instant app starts. It's preferred to do it this way to provide
+ // continuous progress to the useur instead of mysteriously blocking somewhere in the
+ // middle of running an instant app. The default behaviour can be overridden
+ // via gservices.
+ //
+ // Furthermore, dexopt may be skipped, depending on the install scenario and current
+ // state of the device.
+ //
+ // TODO(b/174695087): instantApp and onIncremental should be removed and their install
+ // path moved to SCENARIO_FAST.
+ final boolean performDexopt =
+ (!instantApp || android.provider.Settings.Global.getInt(
+ mPm.mContext.getContentResolver(),
+ android.provider.Settings.Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
+ && !pkg.isDebuggable()
+ && (!onIncremental)
+ && dexoptOptions.isCompilationEnabled();
+
+ if (performDexopt) {
+ // Compile the layout resources.
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
+ mPm.mViewCompiler.compileLayouts(pkg);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ ScanResult result = reconciledPkg.mScanResult;
+
+ // This mirrors logic from commitReconciledScanResultLocked, where the library files
+ // needed for dexopt are assigned.
+ // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
+ // setting needs to be passed to have a comparison, hide it behind an immutable
+ // interface. There's no good reason to have 3 different ways to access the real
+ // PackageSetting object, only one of which is actually correct.
+ PackageSetting realPkgSetting = result.mExistingSettingCopied
+ ? result.mRequest.mPkgSetting : result.mPkgSetting;
+ if (realPkgSetting == null) {
+ realPkgSetting = reconciledPkg.mPkgSetting;
+ }
+
+ // Unfortunately, the updated system app flag is only tracked on this PackageSetting
+ boolean isUpdatedSystemApp = reconciledPkg.mPkgSetting.getPkgState()
+ .isUpdatedSystemApp();
+
+ realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
+
+ mPm.mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
+ null /* instructionSets */,
+ mPm.getOrCreateCompilerPackageStats(pkg),
+ mPm.getDexManager().getPackageUseInfoOrDefault(packageName),
+ dexoptOptions);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Notify BackgroundDexOptService that the package has been changed.
+ // If this is an update of a package which used to fail to compile,
+ // BackgroundDexOptService will remove it from its denylist.
+ // TODO: Layering violation
+ BackgroundDexOptService.notifyPackageChanged(packageName);
+
+ notifyPackageChangeObserversOnUpdate(reconciledPkg);
+ }
+ waitForNativeBinariesExtraction(incrementalStorages);
+ }
+
+ private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
+ final PackageSetting pkgSetting = reconciledPkg.mPkgSetting;
+ final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.mInstallResult;
+ final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.mRemovedInfo;
+
+ PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+ pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName();
+ pkgChangeEvent.version = pkgSetting.versionCode;
+ pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime;
+ pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.mIsUpdate);
+ pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.mDataRemoved);
+ pkgChangeEvent.isDeleted = false;
+
+ mPm.notifyPackageChangeObservers(pkgChangeEvent);
+ }
+
+ static void waitForNativeBinariesExtraction(
+ ArraySet<IncrementalStorage> incrementalStorages) {
+ if (incrementalStorages.isEmpty()) {
+ return;
+ }
+ try {
+ // Native library extraction may take very long time: each page could potentially
+ // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds
+ // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't
+ // make much sense as blocking here doesn't lock up the framework, but only blocks
+ // the installation session and the following ones.
+ Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract");
+ for (int i = 0; i < incrementalStorages.size(); ++i) {
+ IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i);
+ storage.waitForNativeBinariesExtraction();
+ }
+ } finally {
+ Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract");
+ }
+ }
+
+ /**
+ * Ensure that the install reason matches what we know about the package installer (e.g. whether
+ * it is acting on behalf on an enterprise or the user).
+ *
+ * Note that the ordering of the conditionals in this method is important. The checks we perform
+ * are as follows, in this order:
+ *
+ * 1) If the install is being performed by a system app, we can trust the app to have set the
+ * install reason correctly. Thus, we pass through the install reason unchanged, no matter
+ * what it is.
+ * 2) If the install is being performed by a device or profile owner app, the install reason
+ * should be enterprise policy. However, we cannot be sure that the device or profile owner
+ * set the install reason correctly. If the app targets an older SDK version where install
+ * reasons did not exist yet, or if the app author simply forgot, the install reason may be
+ * unset or wrong. Thus, we force the install reason to be enterprise policy.
+ * 3) In all other cases, the install is being performed by a regular app that is neither part
+ * of the system nor a device or profile owner. We have no reason to believe that this app is
+ * acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+ * set to enterprise policy and if so, change it to unknown instead.
+ */
+ private int fixUpInstallReason(String installerPackageName, int installerUid,
+ int installReason) {
+ if (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+ == PERMISSION_GRANTED) {
+ // If the install is being performed by a system app, we trust that app to have set the
+ // install reason correctly.
+ return installReason;
+ }
+ final String ownerPackage = mPm.mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(
+ UserHandle.getUserId(installerUid));
+ if (ownerPackage != null && ownerPackage.equals(installerPackageName)) {
+ // If the install is being performed by a device or profile owner, the install
+ // reason should be enterprise policy.
+ return PackageManager.INSTALL_REASON_POLICY;
+ }
+
+
+ if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+ // If the install is being performed by a regular app (i.e. neither system app nor
+ // device or profile owner), we have no reason to believe that the app is acting on
+ // behalf of an enterprise. If the app set the install reason to enterprise policy,
+ // change it to unknown instead.
+ return PackageManager.INSTALL_REASON_UNKNOWN;
+ }
+
+ // If the install is being performed by a regular app and the install reason was set to any
+ // value but enterprise policy, leave the install reason unchanged.
+ return installReason;
+ }
+
+ public void installStage() {
+ final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+ setTraceMethod("installStage").setTraceCookie(System.identityHashCode(this));
+ msg.obj = this;
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+
+ mPm.mHandler.sendMessage(msg);
+ }
+
+ public void installStage(List<InstallParams> children)
+ throws PackageManagerException {
+ final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+ final MultiPackageInstallParams params =
+ new MultiPackageInstallParams(this, children);
+ params.setTraceMethod("installStageMultiPackage")
+ .setTraceCookie(System.identityHashCode(params));
+ msg.obj = params;
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mPm.mHandler.sendMessage(msg);
+ }
+
+ public void movePackage() {
+ final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+ setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(this));
+ msg.obj = this;
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mPm.mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ final class MultiPackageInstallParams extends HandlerParams {
+ private final List<InstallParams> mChildParams;
+ private final Map<InstallArgs, Integer> mCurrentState;
+
+ MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
+ throws PackageManagerException {
+ super(parent.getUser());
+ if (childParams.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = childParams;
+ for (int i = 0; i < childParams.size(); i++) {
+ final InstallParams childParam = childParams.get(i);
+ childParam.mParentInstallParams = this;
+ }
+ this.mCurrentState = new ArrayMap<>(mChildParams.size());
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (InstallParams params : mChildParams) {
+ params.handleStartCopy();
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (InstallParams params : mChildParams) {
+ params.handleReturnCode();
+ }
+ }
+
+ void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+ mCurrentState.put(args, currentStatus);
+ if (mCurrentState.size() != mChildParams.size()) {
+ return;
+ }
+ int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+ for (Integer status : mCurrentState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ completeStatus = status;
+ break;
+ }
+ }
+ final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
+ for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
+ installRequests.add(new InstallRequest(entry.getKey(),
+ new PackageInstalledInfo(completeStatus)));
+ }
+ processInstallRequestsAsync(
+ completeStatus == PackageManager.INSTALL_SUCCEEDED,
+ installRequests);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/services/core/java/com/android/server/pm/InstallRequest.java
similarity index 62%
copy from core/java/com/android/internal/view/InputBindResult.aidl
copy to services/core/java/com/android/server/pm/InstallRequest.java
index 7ff5c4e..753d012 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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.
@@ -14,6 +14,14 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package com.android.server.pm;
-parcelable InputBindResult;
+final class InstallRequest {
+ public final InstallArgs mArgs;
+ public final PackageInstalledInfo mInstallResult;
+
+ InstallRequest(InstallArgs args, PackageInstalledInfo res) {
+ mArgs = args;
+ mInstallResult = res;
+ }
+}
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/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index fe74889..1b919f9 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -17,10 +17,10 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
-import android.content.pm.PackageParser;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
@@ -801,7 +801,7 @@
long identifier = parser.getAttributeLong(null, "identifier");
int refCount = 0;
byte[] publicKey = parser.getAttributeBytesBase64(null, "value", null);
- PublicKey pub = PackageParser.parsePublicKey(publicKey);
+ PublicKey pub = parsePublicKey(publicKey);
if (pub != null) {
PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
mPublicKeys.put(identifier, pkh);
diff --git a/services/core/java/com/android/server/pm/MoveInfo.java b/services/core/java/com/android/server/pm/MoveInfo.java
new file mode 100644
index 0000000..5ab86d6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MoveInfo.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.server.pm;
+
+final class MoveInfo {
+ final int mMoveId;
+ final String mFromUuid;
+ final String mToUuid;
+ final String mPackageName;
+ final int mAppId;
+ final String mSeInfo;
+ final int mTargetSdkVersion;
+ final String mFromCodePath;
+
+ MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
+ int appId, String seInfo, int targetSdkVersion,
+ String fromCodePath) {
+ mMoveId = moveId;
+ mFromUuid = fromUuid;
+ mToUuid = toUuid;
+ mPackageName = packageName;
+ mAppId = appId;
+ mSeInfo = seInfo;
+ mTargetSdkVersion = targetSdkVersion;
+ mFromCodePath = fromCodePath;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/MoveInstallArgs.java b/services/core/java/com/android/server/pm/MoveInstallArgs.java
new file mode 100644
index 0000000..35827a1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MoveInstallArgs.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.io.File;
+
+/**
+ * Logic to handle movement of existing installed applications.
+ */
+final class MoveInstallArgs extends InstallArgs {
+ private File mCodeFile;
+
+ /** New install */
+ MoveInstallArgs(InstallParams params) {
+ super(params);
+ }
+
+ int copyApk() {
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from "
+ + mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid);
+ }
+ synchronized (mPm.mInstaller) {
+ try {
+ mPm.mInstaller.moveCompleteApp(mMoveInfo.mFromUuid, mMoveInfo.mToUuid,
+ mMoveInfo.mPackageName, mMoveInfo.mAppId, mMoveInfo.mSeInfo,
+ mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, "Failed to move app", e);
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+
+ final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
+ mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName);
+ if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + mCodeFile);
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ int doPreInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp(mMoveInfo.mToUuid);
+ }
+ return status;
+ }
+
+ @Override
+ boolean doRename(int status, ParsedPackage parsedPackage) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp(mMoveInfo.mToUuid);
+ return false;
+ }
+
+ return true;
+ }
+
+ int doPostInstall(int status, int uid) {
+ if (status == PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp(mMoveInfo.mFromUuid);
+ } else {
+ cleanUp(mMoveInfo.mToUuid);
+ }
+ return status;
+ }
+
+ @Override
+ String getCodePath() {
+ return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
+ }
+
+ private void cleanUp(String volumeUuid) {
+ final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
+ final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
+ toPathName);
+ Slog.d(TAG, "Cleaning up " + mMoveInfo.mPackageName + " on " + volumeUuid);
+ final int[] userIds = mPm.mUserManager.getUserIds();
+ synchronized (mPm.mInstallLock) {
+ // Clean up both app data and code
+ // All package moves are frozen until finished
+
+ // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
+ // this task was only focused on moving data on internal storage.
+ // We don't want ART profiles cleared, because they don't move,
+ // so we would be deleting the only copy (b/149200535).
+ final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
+ for (int userId : userIds) {
+ try {
+ mPm.mInstaller.destroyAppData(volumeUuid, mMoveInfo.mPackageName, userId, flags,
+ 0);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ }
+ mPm.removeCodePathLI(codeFile);
+ }
+ }
+
+ void cleanUpResourcesLI() {
+ throw new UnsupportedOperationException();
+ }
+
+ boolean doPostDeleteLI(boolean delete) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/OriginInfo.java b/services/core/java/com/android/server/pm/OriginInfo.java
new file mode 100644
index 0000000..b2fbd32
--- /dev/null
+++ b/services/core/java/com/android/server/pm/OriginInfo.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import java.io.File;
+
+final class OriginInfo {
+ /**
+ * Location where install is coming from, before it has been
+ * copied/renamed into place. This could be a single monolithic APK
+ * file, or a cluster directory. This location may be untrusted.
+ */
+ final File mFile;
+
+ /**
+ * Flag indicating that {@link #mFile} has already been staged, meaning downstream users
+ * don't need to defensively copy the contents.
+ */
+ final boolean mStaged;
+
+ /**
+ * Flag indicating that {@link #mFile} is an already installed app that is being moved.
+ */
+ final boolean mExisting;
+
+ final String mResolvedPath;
+ final File mResolvedFile;
+
+ static OriginInfo fromNothing() {
+ return new OriginInfo(null, false, false);
+ }
+
+ static OriginInfo fromExistingFile(File file) {
+ return new OriginInfo(file, false, true);
+ }
+
+ static OriginInfo fromStagedFile(File file) {
+ return new OriginInfo(file, true, false);
+ }
+
+ private OriginInfo(File file, boolean staged, boolean existing) {
+ mFile = file;
+ mStaged = staged;
+ mExisting = existing;
+
+ if (file != null) {
+ mResolvedPath = file.getAbsolutePath();
+ mResolvedFile = file;
+ } else {
+ mResolvedPath = null;
+ mResolvedFile = 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/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 44f7d88..dd22fd6 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -210,7 +210,7 @@
if (paths.size() != classLoaderContexts.length) {
String[] splitCodePaths = pkg.getSplitCodePaths();
throw new IllegalStateException("Inconsistent information "
- + "between PackageParser.Package and its ApplicationInfo. "
+ + "between AndroidPackage and its ApplicationInfo. "
+ "pkg.getAllCodePaths=" + paths
+ " pkg.getBaseCodePath=" + pkg.getBaseApkPath()
+ " pkg.getSplitCodePaths="
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
new file mode 100644
index 0000000..395f3b4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+
+import dalvik.system.CloseGuard;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class that freezes and kills the given package upon creation, and
+ * unfreezes it upon closing. This is typically used when doing surgery on
+ * app code/data to prevent the app from running while you're working.
+ */
+final class PackageFreezer implements AutoCloseable {
+ private final String mPackageName;
+
+ private final boolean mWeFroze;
+
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ @NonNull
+ private final PackageManagerService mPm;
+
+ /**
+ * Create and return a stub freezer that doesn't actually do anything,
+ * typically used when someone requested
+ * {@link PackageManager#INSTALL_DONT_KILL_APP} or
+ * {@link PackageManager#DELETE_DONT_KILL_APP}.
+ */
+ PackageFreezer(PackageManagerService pm) {
+ mPm = pm;
+ mPackageName = null;
+ mWeFroze = false;
+ mCloseGuard.open("close");
+ }
+
+ PackageFreezer(String packageName, int userId, String killReason,
+ PackageManagerService pm) {
+ mPm = pm;
+ mPackageName = packageName;
+ final PackageSetting ps;
+ synchronized (mPm.mLock) {
+ mWeFroze = mPm.mFrozenPackages.add(mPackageName);
+ ps = mPm.mSettings.getPackageLPr(mPackageName);
+ }
+ if (ps != null) {
+ mPm.killApplication(ps.name, ps.appId, userId, killReason);
+ }
+ mCloseGuard.open("close");
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ synchronized (mPm.mLock) {
+ if (mWeFroze) {
+ mPm.mFrozenPackages.remove(mPackageName);
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
new file mode 100644
index 0000000..afe6bb2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.content.pm.PackageParser;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.util.ArrayList;
+
+final class PackageInstalledInfo {
+ String mName;
+ int mUid;
+ // The set of users that originally had this package installed.
+ int[] mOrigUsers;
+ // The set of users that now have this package installed.
+ int[] mNewUsers;
+ AndroidPackage mPkg;
+ int mReturnCode;
+ String mReturnMsg;
+ String mInstallerPackageName;
+ PackageRemovedInfo mRemovedInfo;
+ // The set of packages consuming this shared library or null if no consumers exist.
+ ArrayList<AndroidPackage> mLibraryConsumers;
+ PackageFreezer mFreezer;
+
+ // In some error cases we want to convey more info back to the observer
+ String mOrigPackage;
+ String mOrigPermission;
+
+ PackageInstalledInfo(int currentStatus) {
+ mReturnCode = currentStatus;
+ mUid = -1;
+ mPkg = null;
+ mRemovedInfo = null;
+ }
+
+ public void setError(int code, String msg) {
+ setReturnCode(code);
+ setReturnMessage(msg);
+ Slog.w(TAG, msg);
+ }
+
+ public void setError(String msg, PackageParser.PackageParserException e) {
+ setReturnCode(e.error);
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
+ Slog.w(TAG, msg, e);
+ }
+
+ public void setError(String msg, PackageManagerException e) {
+ mReturnCode = e.error;
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
+ Slog.w(TAG, msg, e);
+ }
+
+ public void setReturnCode(int returnCode) {
+ mReturnCode = returnCode;
+ }
+
+ private void setReturnMessage(String returnMsg) {
+ mReturnMsg = returnMsg;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e605652..fdbcf85 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) {
@@ -2369,8 +2384,7 @@
private void verifyNonStaged()
throws PackageManagerException {
- final PackageManagerService.VerificationParams verifyingSession =
- prepareForVerification();
+ final VerificationParams verifyingSession = prepareForVerification();
if (isMultiPackage()) {
final List<PackageInstallerSession> childSessions = getChildSessions();
// Spot check to reject a non-staged multi package install of APEXes and APKs.
@@ -2380,14 +2394,14 @@
PackageManager.INSTALL_FAILED_SESSION_INVALID,
"Non-staged multi package install of APEX and APK packages is not supported");
}
- List<PackageManagerService.VerificationParams> verifyingChildSessions =
+ List<VerificationParams> verifyingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
- final PackageManagerService.VerificationParams verifyingChildSession =
+ final VerificationParams verifyingChildSession =
session.prepareForVerification();
verifyingChildSessions.add(verifyingChildSession);
} catch (PackageManagerException e) {
@@ -2401,9 +2415,9 @@
failure.error, failure.getLocalizedMessage(), null);
return;
}
- mPm.verifyStage(verifyingSession, verifyingChildSessions);
+ verifyingSession.verifyStage(verifyingChildSessions);
} else {
- mPm.verifyStage(verifyingSession);
+ verifyingSession.verifyStage();
}
}
@@ -2418,21 +2432,20 @@
private void installNonStaged()
throws PackageManagerException {
- final PackageManagerService.InstallParams installingSession = makeInstallParams();
+ final InstallParams installingSession = makeInstallParams();
if (installingSession == null) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session should contain at least one apk session for installation");
}
if (isMultiPackage()) {
final List<PackageInstallerSession> childSessions = getChildSessions();
- List<PackageManagerService.InstallParams> installingChildSessions =
- new ArrayList<>(childSessions.size());
+ List<InstallParams> installingChildSessions = new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
- final PackageManagerService.InstallParams installingChildSession =
+ final InstallParams installingChildSession =
session.makeInstallParams();
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
@@ -2448,20 +2461,19 @@
failure.error, failure.getLocalizedMessage(), null);
return;
}
- mPm.installStage(installingSession, installingChildSessions);
+ installingSession.installStage(installingChildSessions);
} else {
- mPm.installStage(installingSession);
+ installingSession.installStage();
}
}
/**
* Stages this session for verification and returns a
- * {@link PackageManagerService.VerificationParams} representing this new staged state or null
+ * {@link VerificationParams} representing this new staged state or null
* in case permissions need to be requested before verification can proceed.
*/
@NonNull
- private PackageManagerService.VerificationParams prepareForVerification()
- throws PackageManagerException {
+ private VerificationParams prepareForVerification() throws PackageManagerException {
assertNotLocked("makeSessionActive");
synchronized (mLock) {
@@ -2588,9 +2600,9 @@
@GuardedBy("mLock")
@Nullable
/**
- * Returns a {@link com.android.server.pm.PackageManagerService.VerificationParams}
+ * Returns a {@link com.android.server.pm.VerificationParams}
*/
- private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
+ private VerificationParams makeVerificationParamsLocked() {
final IPackageInstallObserver2 localObserver;
if (!hasParentSessionId()) {
// Avoid attaching this observer to child session since they won't use it.
@@ -2623,8 +2635,8 @@
mRelinquished = true;
- return mPm.new VerificationParams(user, stageDir, localObserver, params,
- mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
+ return new VerificationParams(user, stageDir, localObserver, params,
+ mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite, mPm);
}
private void onVerificationComplete() {
@@ -2641,10 +2653,10 @@
/**
* Stages this session for install and returns a
- * {@link PackageManagerService.InstallParams} representing this new staged state.
+ * {@link InstallParams} representing this new staged state.
*/
@Nullable
- private PackageManagerService.InstallParams makeInstallParams()
+ private InstallParams makeInstallParams()
throws PackageManagerException {
synchronized (mLock) {
if (mDestroyed) {
@@ -2707,8 +2719,8 @@
}
synchronized (mLock) {
- return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
- mSigningDetails, mInstallerUid, mPackageLite);
+ return new InstallParams(stageDir, localObserver, params, mInstallSource, user,
+ mSigningDetails, mInstallerUid, mPackageLite, mPm);
}
}
@@ -2763,7 +2775,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 +2838,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 +3458,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 1fda347..b44e2ed 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,14 +21,10 @@
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
-import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
-import static android.content.Intent.EXTRA_PACKAGE_NAME;
-import static android.content.Intent.EXTRA_VERSION_CODE;
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -36,36 +32,17 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
-import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
-import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
-import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
-import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
-import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.MATCH_ALL;
@@ -95,11 +72,9 @@
import static android.content.pm.PackageManager.TYPE_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
-import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
-import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -118,7 +93,6 @@
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
-import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
@@ -132,6 +106,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;
@@ -210,8 +185,6 @@
import android.content.pm.PackageManagerInternal;
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;
@@ -233,10 +206,8 @@
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
-import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -247,8 +218,6 @@
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
@@ -279,7 +248,6 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SELinux;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
@@ -288,7 +256,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.IncrementalManager;
-import android.os.incremental.IncrementalStorage;
import android.os.incremental.PerUidReadTimeouts;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
@@ -303,11 +270,9 @@
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
-import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
import android.stats.storage.StorageEnums;
import android.system.ErrnoException;
-import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -393,7 +358,6 @@
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.LegacyPermissionManagerService;
-import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -416,7 +380,6 @@
import com.android.server.utils.Watcher;
import com.android.server.wm.ActivityTaskManagerInternal;
-import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -431,7 +394,6 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -442,10 +404,8 @@
import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
-import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -531,7 +491,7 @@
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
public static final boolean DEBUG_PACKAGE_SCANNING = false;
- private static final boolean DEBUG_VERIFY = false;
+ static final boolean DEBUG_VERIFY = false;
public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
@@ -544,7 +504,7 @@
public static final boolean DEBUG_DEXOPT = false;
static final boolean DEBUG_ABI_SELECTION = false;
- private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
@@ -552,7 +512,7 @@
private static final boolean HIDE_EPHEMERAL_APIS = false;
- private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
+ static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
@@ -680,43 +640,10 @@
private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS;
/**
- * Whether verification is enabled by default.
- */
- private static final boolean DEFAULT_VERIFY_ENABLE = true;
-
- /**
- * Whether integrity verification is enabled by default.
- */
- private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
-
- /**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
- private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
-
- /**
- * The default maximum time to wait for the integrity verification to return in
- * milliseconds.
- */
- private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
-
- /**
- * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
- * rollback within that period, the install will proceed without rollback enabled.
- *
- * <p>If flag value is negative, the default value will be assigned.
- *
- * Flag type: {@code long}
- * Namespace: NAMESPACE_ROLLBACK
- */
- private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
-
- /**
- * The default duration to wait for rollback to be enabled in
- * milliseconds.
- */
- private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
+ static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
* Default IncFs timeouts. Maximum values in IncFs is 1hr.
@@ -776,7 +703,7 @@
public static final String PLATFORM_PACKAGE_NAME = "android";
- private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
+ static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String PACKAGE_SCHEME = "package";
@@ -943,7 +870,7 @@
boolean mFirstBoot;
- private final boolean mIsEngBuild;
+ final boolean mIsEngBuild;
private final boolean mIsUserDebugBuild;
private final String mIncrementalVersion;
@@ -974,16 +901,11 @@
@GuardedBy("mLock")
final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
- @GuardedBy("mLock")
- private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
-
private final ModuleInfoProvider mModuleInfoProvider;
- private final ApexManager mApexManager;
+ final ApexManager mApexManager;
- private final Injector mInjector;
-
- private final SystemWrapper mSystemWrapper;
+ final Injector mInjector;
/**
* The list of all system partitions that may contain packages in ascending order of
@@ -1402,17 +1324,16 @@
public ArrayMap<String, AndroidPackage> packages;
public boolean enableFreeCacheV2;
public int sdkVersion;
- public SystemWrapper systemWrapper;
public File appInstallDir;
public File appLib32InstallDir;
public boolean isEngBuild;
public boolean isUserDebugBuild;
public int sdkInt = Build.VERSION.SDK_INT;
- public String incrementalVersion = Build.VERSION.INCREMENTAL;
+ public final String incrementalVersion = Build.VERSION.INCREMENTAL;
}
@Watched
- private final AppsFilter mAppsFilter;
+ final AppsFilter mAppsFilter;
final PackageParser2.Callback mPackageParserCallback;
@@ -1460,24 +1381,24 @@
final ArtManagerService mArtManagerService;
- private final PackageDexOptimizer mPackageDexOptimizer;
+ final PackageDexOptimizer mPackageDexOptimizer;
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
private final DexManager mDexManager;
- private final ViewCompiler mViewCompiler;
+ final ViewCompiler mViewCompiler;
- private AtomicInteger mNextMoveId = new AtomicInteger();
+ private final AtomicInteger mNextMoveId = new AtomicInteger();
private final MoveCallbacks mMoveCallbacks;
// Cache of users who need badging.
private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
/** Token for keys in mPendingVerification. */
- private int mPendingVerificationToken = 0;
+ int mPendingVerificationToken = 0;
/** Token for keys in mPendingEnableRollback. */
- private int mPendingEnableRollbackToken = 0;
+ int mPendingEnableRollbackToken = 0;
@Watched(manual = true)
volatile boolean mSystemReady;
@@ -1510,7 +1431,7 @@
/** Activity used to install instant applications */
@Watched(manual = true)
- private ActivityInfo mInstantAppInstallerActivity;
+ ActivityInfo mInstantAppInstallerActivity;
@Watched(manual = true)
private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
@@ -1518,7 +1439,7 @@
mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
// Internal interface for permission manager
- private final PermissionManagerServiceInternal mPermissionManager;
+ final PermissionManagerServiceInternal mPermissionManager;
@Watched
private final ComponentResolver mComponentResolver;
@@ -1533,7 +1454,7 @@
private Future<?> mPrepareAppDataFuture;
- private final IncrementalManager mIncrementalManager;
+ final IncrementalManager mIncrementalManager;
private final DefaultAppProvider mDefaultAppProvider;
@@ -1645,7 +1566,7 @@
final UserManagerService mUserManager;
// Stores a list of users whose package restrictions file needs to be updated
- private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
+ private final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
@@ -1671,31 +1592,6 @@
// XML tags for backup/restore of various bits of state
private static final String TAG_PREFERRED_BACKUP = "pa";
private static final String TAG_DEFAULT_APPS = "da";
- private static final String TAG_INTENT_FILTER_VERIFICATION = "iv";
-
- private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup";
- private static final String TAG_ALL_GRANTS = "rt-grants";
- private static final String TAG_GRANT = "grant";
- private static final String ATTR_PACKAGE_NAME = "pkg";
-
- private static final String TAG_PERMISSION = "perm";
- private static final String ATTR_PERMISSION_NAME = "name";
- private static final String ATTR_IS_GRANTED = "g";
- private static final String ATTR_USER_SET = "set";
- private static final String ATTR_USER_FIXED = "fixed";
- private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
-
- // System/policy permission grants are not backed up
- private static final int SYSTEM_RUNTIME_GRANT_MASK =
- FLAG_PERMISSION_POLICY_FIXED
- | FLAG_PERMISSION_SYSTEM_FIXED
- | FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-
- // And we back up these user-adjusted states
- private static final int USER_RUNTIME_GRANT_MASK =
- FLAG_PERMISSION_USER_SET
- | FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_REVOKED_COMPAT;
final @Nullable String mRequiredVerifierPackage;
final @NonNull String mRequiredInstallerPackage;
@@ -1838,7 +1734,7 @@
private final Watcher mWatcher = new Watcher() {
@Override
public void onChange(@Nullable Watchable what) {
- PackageManagerService.this.onChange(what);
+ PackageManagerService.onChange(what);
}
};
@@ -1959,7 +1855,7 @@
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
- public @interface LiveImplementation {
+ @interface LiveImplementation {
// A Computer method must be annotated with one of the following values:
// MANDATORY - the method must be overridden in ComputerEngineLive. The
// format of the override is a call to the super method, wrapped in a
@@ -2324,11 +2220,10 @@
}
}
- List<ResolveInfo> result = applyPostResolutionFilter(
+ return applyPostResolutionFilter(
list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
resolveForStart,
userId, intent);
- return result;
}
QueryIntentActivitiesResult lockedResult =
@@ -3969,10 +3864,8 @@
return true;
}
// TODO(b/122900055) Change/Remove this and replace with new permission role.
- if (mAppPredictionServicePackage != null
- && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
- return true;
- }
+ return mAppPredictionServicePackage != null
+ && isCallerSameApp(mAppPredictionServicePackage, callingUid);
}
return false;
}
@@ -4074,10 +3967,7 @@
if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
return true;
}
- if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) {
- return true;
- }
- return false;
+ return isComponentVisibleToInstantApp(component, TYPE_PROVIDER);
}
public final boolean isComponentVisibleToInstantApp(
@@ -4314,11 +4204,8 @@
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final boolean callerIsInstantApp = instantAppPkgName != null;
if (ps == null) {
- if (callerIsInstantApp) {
- // pretend the application exists, but, needs to be filtered
- return true;
- }
- return false;
+ // pretend the application exists, but, needs to be filtered
+ return callerIsInstantApp;
}
// if the target and caller are the same application, don't filter
if (isCallerSameApp(ps.name, callingUid)) {
@@ -5046,13 +4933,13 @@
// a live computer.
private final AtomicInteger mReusedLive = new AtomicInteger(0);
- private PackageManagerService mService;
+ private final PackageManagerService mService;
ComputerTracker(PackageManagerService s) {
mService = s;
}
private ThreadComputer live() {
- ThreadComputer current = mService.sThreadComputer.get();
+ ThreadComputer current = sThreadComputer.get();
if (current.mRefCount > 0) {
current.acquire();
mReusedLive.incrementAndGet();
@@ -5063,7 +4950,7 @@
}
private ThreadComputer snapshot() {
- ThreadComputer current = mService.sThreadComputer.get();
+ ThreadComputer current = sThreadComputer.get();
if (current.mRefCount > 0) {
current.acquire();
mReusedSnapshot.incrementAndGet();
@@ -5623,13 +5510,13 @@
// set from outside classes. The attribute may be set to true anywhere, although it
// should only be set true while holding mLock. However, the attribute id guaranteed
// to be set false only while mLock and mSnapshotLock are both held.
- private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
+ private static final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
// The package manager that is using snapshots.
private static PackageManagerService sSnapshotConsumer = null;
// If true, the snapshot is corked. Do not create a new snapshot but use the live
// computer. This throttles snapshot creation during periods of churn in Package
// Manager.
- private static AtomicInteger sSnapshotCorked = new AtomicInteger(0);
+ private static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
/**
* This class records the Computer being used by a thread and the Computer's reference
@@ -5657,7 +5544,7 @@
}
}
}
- private static ThreadLocal<ThreadComputer> sThreadComputer = new ThreadLocal<>() {
+ private static final ThreadLocal<ThreadComputer> sThreadComputer = new ThreadLocal<>() {
@Override protected ThreadComputer initialValue() {
return new ThreadComputer();
}};
@@ -5834,10 +5721,10 @@
break;
}
case SEND_PENDING_BROADCAST: {
- String packages[];
- ArrayList<String> components[];
+ String[] packages;
+ ArrayList<String>[] components;
int size = 0;
- int uids[];
+ int[] uids;
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
size = mPendingBroadcasts.size();
@@ -5883,8 +5770,8 @@
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
- if (data != null && data.res.freezer != null) {
- data.res.freezer.close();
+ if (data != null && data.res.mFreezer != null) {
+ data.res.mFreezer.close();
}
if (data != null && data.mPostInstallRunnable != null) {
@@ -5893,19 +5780,19 @@
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
- final boolean killApp = (args.installFlags
+ final boolean killApp = (args.mInstallFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
- final boolean virtualPreload = ((args.installFlags
+ final boolean virtualPreload = ((args.mInstallFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
handlePackagePostInstall(parentRes, killApp, virtualPreload,
- didRestore, args.installSource.installerPackageName, args.observer,
- args.mDataLoaderType);
+ didRestore, args.mInstallSource.installerPackageName,
+ args.mObserver, args.mDataLoaderType);
// Log tracing if needed
- if (args.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
- args.traceCookie);
+ if (args.mTraceMethod != null) {
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod,
+ args.mTraceCookie);
}
} else if (DEBUG_INSTALL) {
// No post-install when we run restore from installExistingPackageForUser
@@ -5964,9 +5851,10 @@
if ((state != null) && !state.isVerificationComplete()
&& !state.timeoutExtended()) {
final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
- 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 +5870,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);
}
@@ -6005,9 +5893,10 @@
if (state != null && !state.isIntegrityVerificationComplete()) {
final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
- 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 +5906,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()) {
@@ -6050,14 +5940,15 @@
if (state.isVerificationComplete()) {
final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
if (state.isInstallAllowed()) {
broadcastPackageVerified(verificationId, originUri,
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()) {
@@ -6084,7 +5975,7 @@
final int response = (Integer) msg.obj;
final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
state.setIntegrityVerificationResult(response);
@@ -6092,7 +5983,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()) {
@@ -6129,7 +6021,7 @@
mPendingEnableRollback.remove(enableRollbackToken);
if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
Slog.w(TAG, "Failed to enable rollback for " + originUri);
Slog.w(TAG, "Continuing with installation of " + originUri);
}
@@ -6146,7 +6038,7 @@
final VerificationParams params =
mPendingEnableRollback.get(enableRollbackToken);
if (params != null) {
- final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
Slog.w(TAG, "Enable rollback timed out for " + originUri);
mPendingEnableRollback.remove(enableRollbackToken);
@@ -6187,20 +6079,21 @@
private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
- boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
- final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
- final String packageName = res.name;
+ boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
+ final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
+ final String packageName = res.mName;
final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
final boolean removedBeforeUpdate = (pkgSetting == null)
- || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath()));
+ || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
+ res.mPkg.getPath()));
if (succeeded && removedBeforeUpdate) {
Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ "could be executed");
- res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED;
- res.returnMsg = "Package was removed before install could complete.";
+ res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
+ res.mReturnMsg = "Package was removed before install could complete.";
// Remove the update failed package's older resources safely now
- InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+ InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
if (args != null) {
synchronized (mInstallLock) {
args.doPostDeleteLI(true);
@@ -6215,19 +6108,19 @@
mPerUidReadTimeoutsCache = null;
// Send the removed broadcasts
- if (res.removedInfo != null) {
- res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
+ if (res.mRemovedInfo != null) {
+ res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
final String installerPackageName =
- res.installerPackageName != null
- ? res.installerPackageName
- : res.removedInfo != null
- ? res.removedInfo.installerPackageName
+ res.mInstallerPackageName != null
+ ? res.mInstallerPackageName
+ : res.mRemovedInfo != null
+ ? res.mRemovedInfo.mInstallerPackageName
: null;
synchronized (mLock) {
- mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
+ mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
}
// Determine the set of users who are adding this package for
@@ -6236,10 +6129,9 @@
int[] firstInstantUserIds = EMPTY_INT_ARRAY;
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
- final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
- final PackageSetting ps = pkgSetting;
- for (int newUser : res.newUsers) {
- final boolean isInstantApp = ps.getInstantApp(newUser);
+ final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0;
+ for (int newUser : res.mNewUsers) {
+ final boolean isInstantApp = pkgSetting.getInstantApp(newUser);
if (allNewUsers) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
@@ -6249,7 +6141,7 @@
continue;
}
boolean isNew = true;
- for (int origUser : res.origUsers) {
+ for (int origUser : res.mOrigUsers) {
if (origUser == newUser) {
isNew = false;
break;
@@ -6271,20 +6163,20 @@
}
// Send installed broadcasts if the package is not a static shared lib.
- if (res.pkg.getStaticSharedLibName() == null) {
- mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath());
+ if (res.mPkg.getStaticSharedLibName() == null) {
+ mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
- int appId = UserHandle.getAppId(res.uid);
- boolean isSystem = res.pkg.isSystem();
+ int appId = UserHandle.getAppId(res.mUid);
+ boolean isSystem = res.mPkg.isSystem();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
+ extras.putInt(Intent.EXTRA_UID, res.mUid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
@@ -6294,7 +6186,7 @@
synchronized (mLock) {
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageSettingInternal(res.name, Process.SYSTEM_UID),
+ getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
updateUserIds, mSettings.getPackagesLocked());
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -6332,7 +6224,7 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList,
+ updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
null);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
@@ -6353,7 +6245,7 @@
null /*broadcastAllowList*/,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
.toBundle());
- } else if (launchedForRestore && !res.pkg.isSystem()) {
+ } else if (launchedForRestore && !res.mPkg.isSystem()) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
@@ -6365,15 +6257,15 @@
}
// Send broadcast package appeared if external for all users
- if (res.pkg.isExternalStorage()) {
+ if (res.mPkg.isExternalStorage()) {
if (!update) {
final StorageManager storage = mInjector.getSystemService(
StorageManager.class);
VolumeInfo volume =
storage.findVolumeByUuid(
- res.pkg.getStorageUuid().toString());
+ res.mPkg.getStorageUuid().toString());
int packageExternalStorageType =
- getPackageExternalStorageType(volume, res.pkg.isExternalStorage());
+ getPackageExternalStorageType(volume, res.mPkg.isExternalStorage());
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
FrameworkStatsLog.write(
@@ -6382,17 +6274,16 @@
}
}
if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
+ Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
}
- final int[] uidArray = new int[]{res.pkg.getUid()};
+ final int[] uidArray = new int[]{res.mPkg.getUid()};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
- } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
- int[] allUsers = mInjector.getUserManagerService().getUserIds();
- for (int i = 0; i < res.libraryConsumers.size(); i++) {
- AndroidPackage pkg = res.libraryConsumers.get(i);
+ } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
+ for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
+ AndroidPackage pkg = res.mLibraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
@@ -6404,14 +6295,14 @@
if (firstUserIds != null && firstUserIds.length > 0) {
for (int userId : firstUserIds) {
restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
- pkgSetting.getInstallReason(userId), userId);
+ userId);
}
}
if (allNewUsers && !update) {
- notifyPackageAdded(packageName, res.uid);
+ notifyPackageAdded(packageName, res.mUid);
} else {
- notifyPackageChanged(packageName, res.uid);
+ notifyPackageChanged(packageName, res.mUid);
}
// Log current value of "unknown sources" setting
@@ -6419,7 +6310,7 @@
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
- InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+ InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
if (args != null) {
if (!killApp) {
// If we didn't kill the app, defer the deletion of code/resource files, since
@@ -6478,7 +6369,7 @@
}
}
- private void notifyInstallObserver(String packageName) {
+ void notifyInstallObserver(String packageName) {
Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
mNoKillInstallObservers.remove(packageName);
@@ -6487,13 +6378,13 @@
}
}
- private void notifyInstallObserver(PackageInstalledInfo info,
+ void notifyInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(info);
- installObserver.onPackageInstalled(info.name, info.returnCode,
- info.returnMsg, extras);
+ installObserver.onPackageInstalled(info.mName, info.mReturnCode,
+ info.mReturnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
@@ -6507,7 +6398,7 @@
private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
- String packageName = info.pkg.getPackageName();
+ String packageName = info.mPkg.getPackageName();
mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -6612,7 +6503,7 @@
return StorageEnums.UNKNOWN;
}
- private StorageEventListener mStorageListener = new StorageEventListener() {
+ private final StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
if (vol.type == VolumeInfo.TYPE_PRIVATE) {
@@ -6666,19 +6557,19 @@
Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
- switch (res.returnCode) {
+ switch (res.mReturnCode) {
case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
extras = new Bundle();
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
- res.origPermission);
+ res.mOrigPermission);
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
- res.origPackage);
+ res.mOrigPackage);
break;
}
case PackageManager.INSTALL_SUCCEEDED: {
extras = new Bundle();
extras.putBoolean(Intent.EXTRA_REPLACING,
- res.removedInfo != null && res.removedInfo.removedPackage != null);
+ res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null);
break;
}
}
@@ -6867,7 +6758,7 @@
* reasons. This simply requests that the copy takes place and awaits confirmation of its
* completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
*/
- private static void requestCopyPreoptedFiles(Injector injector) {
+ private static void requestCopyPreoptedFiles() {
final int WAIT_TIME_MS = 100;
final String CP_PREOPT_PROPERTY = "sys.cppreopt";
if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
@@ -7042,7 +6933,6 @@
mPackages.putAll(testParams.packages);
mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
mSdkVersion = testParams.sdkVersion;
- mSystemWrapper = testParams.systemWrapper;
mAppInstallDir = testParams.appInstallDir;
mAppLib32InstallDir = testParams.appLib32InstallDir;
mIsEngBuild = testParams.isEngBuild;
@@ -7072,7 +6962,6 @@
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
- mSystemWrapper = injector.getSystemWrapper();
mContext = injector.getContext();
mFactoryTest = factoryTest;
@@ -7179,7 +7068,7 @@
}
}
- mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
+ mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager, mPmInternal);
mDirsToScanAsSystem = new ArrayList<>();
mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
@@ -7255,7 +7144,7 @@
mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
if (!mOnlyCore && mFirstBoot) {
- requestCopyPreoptedFiles(mInjector);
+ requestCopyPreoptedFiles();
}
String customResolverActivityName = Resources.getSystem().getString(
@@ -7975,7 +7864,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 =
@@ -8137,7 +8026,7 @@
}
@GuardedBy("mLock")
- private void updateInstantAppInstallerLocked(String modifiedPackage) {
+ void updateInstantAppInstallerLocked(String modifiedPackage) {
// we're only interested in updating the installer appliction when 1) it's not
// already set or 2) the modified package is the installer
if (mInstantAppInstallerActivity != null
@@ -8406,11 +8295,7 @@
return null;
}
synchronized (mLock) {
- final ComponentName instantAppResolver = getInstantAppResolverLPr();
- if (instantAppResolver == null) {
- return null;
- }
- return instantAppResolver;
+ return getInstantAppResolverLPr();
}
}
@@ -8634,7 +8519,7 @@
if (ps != null) {
final PackageUserState state = ps.readUserState(userId);
if (state != null) {
- return PackageParser.isAvailable(state);
+ return checkUseInstalledOrHidden(p, ps, state, 0 /*flags*/);
}
}
}
@@ -8666,16 +8551,6 @@
flags, filterCallingUid, userId);
}
- private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
- return mComputer.isComponentVisibleToInstantApp(component);
- }
-
- private boolean isComponentVisibleToInstantApp(
- @Nullable ComponentName component, @ComponentType int type) {
- return mComputer.isComponentVisibleToInstantApp(
- component, type);
- }
-
/**
* Returns whether or not access to the application should be filtered.
* <p>
@@ -8994,14 +8869,13 @@
if (freeBytesRequired > 0) {
smInternal.freeCache(volumeUuid, freeBytesRequired);
}
- if (file.getUsableSpace() >= bytes) return;
} else {
try {
mInstaller.freeCache(volumeUuid, bytes, 0, 0);
} catch (InstallerException ignored) {
}
- if (file.getUsableSpace() >= bytes) return;
}
+ if (file.getUsableSpace() >= bytes) return;
throw new IOException("Failed to free " + bytes + " on storage device at " + file);
}
@@ -9015,7 +8889,6 @@
final long now = System.currentTimeMillis();
synchronized (mLock) {
- final int[] allUsers = mUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
final WatchedLongSparseArray<SharedLibraryInfo> versionedLib
@@ -9128,14 +9001,6 @@
wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
}
- private int updateFlagsForResolve(int flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly,
- boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- return mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, onlyExposedExplicitly,
- isImplicitImageCaptureIntentAndNotSetByDpc);
- }
-
@Override
public int getTargetSdkVersion(String packageName) {
synchronized (mLock) {
@@ -9555,7 +9420,7 @@
}
@GuardedBy("mLock")
- private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
+ void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
SparseArray<String> changedPackages = mChangedPackages.get(userId);
@@ -9909,7 +9774,7 @@
* external storage) is less than the version where package signatures
* were updated, return true.
*/
- private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
+ boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
@@ -9917,7 +9782,7 @@
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
- private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
+ boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
@@ -10055,24 +9920,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;
}
}
@@ -10288,7 +10155,7 @@
userId);
// Find any earlier preferred or last chosen entries and nuke them
findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, 0, false, true, false, userId);
+ intent, resolvedType, flags, query, false, true, false, userId);
// Add the new activity as the last chosen for this filter
addPreferredActivity(filter, match, null, activity, false, userId,
"Setting last chosen", false);
@@ -10304,7 +10171,7 @@
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, 0, false, false, false, userId);
+ intent, resolvedType, flags, query, false, false, false, userId);
}
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
@@ -10346,7 +10213,7 @@
// If we have saved a preference for a preferred activity for
// this Intent, use that.
ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
- flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered);
+ flags, query, true, false, debug, userId, queryMayBeFiltered);
if (ri != null) {
return ri;
}
@@ -10523,17 +10390,17 @@
}
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
- List<ResolveInfo> query, int priority, boolean always,
+ List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId) {
return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId,
+ intent, resolvedType, flags, query, always, removeMatches, debug, userId,
UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
}
// TODO: handle preferred activities missing while user has amnesia
/** <b>must not hold {@link #mLock}</b> */
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
- List<ResolveInfo> query, int priority, boolean always,
+ List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
if (Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
@@ -10841,16 +10708,6 @@
filterCallingUid, userId, resolveForStart, allowDynamicSplits);
}
- private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
- Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
- boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
- String instantAppPkgName) {
- return mComputer.queryIntentActivitiesInternalBody(
- intent, resolvedType, flags, filterCallingUid, userId,
- resolveForStart, allowDynamicSplits, pkgName,
- instantAppPkgName);
- }
-
private static class CrossProfileDomainInfo {
/* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
ResolveInfo resolveInfo;
@@ -11651,14 +11508,6 @@
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
- return resolveContentProviderInternal(name, flags, userId);
- }
-
- public ProviderInfo resolveContentProvider(String name, int flags, int userId, int callingUid) {
- return resolveContentProviderInternal(name, flags, userId, callingUid);
- }
-
- private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
return resolveContentProviderInternal(name, flags, userId, Binder.getCallingUid());
}
@@ -11894,9 +11743,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);
@@ -11956,10 +11804,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);
}
@@ -11979,7 +11831,7 @@
return;
}
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+ clearAppProfilesLIF(pkg);
if (DEBUG_INSTALL) {
Slog.d(TAG, originalPkgSetting.name
+ " clear profile due to version change "
@@ -12016,8 +11868,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);
}
@@ -12155,11 +12005,12 @@
null, disabledPkgSetting /* pkgSetting */,
null /* disabledPkgSetting */, null /* originalPkgSetting */,
null, parseFlags, scanFlags, isPlatformPackage, user, null);
- applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true);
+ applyPolicy(parsedPackage, scanFlags, mPlatformPackage, true);
final ScanResult scanResult =
scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
- if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
- scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
+ if (scanResult.mExistingSettingCopied
+ && scanResult.mRequest.mPkgSetting != null) {
+ scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
}
}
}
@@ -12206,7 +12057,7 @@
// for the package. Which means it needs to be finalized here to cache derived fields.
// This is relevant for cases where the disabled system package is used for flags or
// other metadata.
- ((ParsedPackage) parsedPackage).hideAsFinal();
+ parsedPackage.hideAsFinal();
throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+ " at " + parsedPackage.getPath() + " ignored: updated version "
+ pkgSetting.versionCode + " better than this "
@@ -12258,7 +12109,7 @@
parsedPackage.getPackageName(),
"scanPackageInternalLI")) {
deletePackageLIF(parsedPackage.getPackageName(), null, true,
- mUserManager.getUserIds(), 0, null, false, null);
+ mUserManager.getUserIds(), 0, null, false);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
@@ -12295,11 +12146,11 @@
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user, null);
- if (scanResult.success) {
+ if (scanResult.mSuccess) {
synchronized (mLock) {
boolean appIdCreated = false;
try {
- final String pkgName = scanResult.pkgSetting.name;
+ final String pkgName = scanResult.mPkgSetting.name;
final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
new ReconcileRequest(
Collections.singletonMap(pkgName, scanResult),
@@ -12331,19 +12182,17 @@
if (pkgSetting != null && pkgSetting.isPackageLoading()) {
// Continue monitoring loading progress of active incremental packages
final IncrementalStatesCallback incrementalStatesCallback =
- new IncrementalStatesCallback(parsedPackage.getPackageName(),
- UserHandle.getUid(UserHandle.USER_ALL, pkgSetting.appId),
- getInstalledUsers(pkgSetting, UserHandle.USER_ALL));
+ new IncrementalStatesCallback(parsedPackage.getPackageName(), this);
pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
- new IncrementalProgressListener(parsedPackage.getPackageName()));
+ new IncrementalProgressListener(parsedPackage.getPackageName(), this));
}
}
- return scanResult.pkgSetting.pkg;
+ return scanResult.mPkgSetting.pkg;
}
// TODO:(b/135203078): Move to parsing
- private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
+ static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
// Derive the new package synthetic package name
parsedPackage.setPackageName(toStaticSharedLibraryPackageName(
parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibVersion()));
@@ -12354,13 +12203,6 @@
return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
}
- static String fixProcessName(String defProcessName, String processName) {
- if (processName == null) {
- return defProcessName;
- }
- return processName;
- }
-
/**
* Enforces that only the system UID or root's UID can call a method exposed
* via Binder.
@@ -12403,24 +12245,6 @@
}
/**
- * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
- * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
- *
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param requirePermissionWhenSameUser When {@code true}, still require the cross user
- * permission to be held even if the callingUid and userId
- * reference the same user.
- * @param message the message to log on security exception
- */
- private void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell,
- boolean requirePermissionWhenSameUser, String message) {
- mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell,
- requirePermissionWhenSameUser, message);
- }
-
- /**
* Checks if the request is from the system or an app that has the appropriate cross-user
* permissions defined as follows:
* <ul>
@@ -12440,10 +12264,6 @@
requireFullPermission, checkShell, message);
}
- private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
- return mComputer.isSameProfileGroup(callerUserId, userId);
- }
-
private static String buildInvalidCrossUserPermissionMessage(int callingUid,
@UserIdInt int userId, String message, boolean requireFullPermission) {
StringBuilder builder = new StringBuilder();
@@ -13095,7 +12915,7 @@
return versionedLib.get(version);
}
- private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
+ SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
pkg.getStaticSharedLibName());
if (versionedLib == null) {
@@ -13115,13 +12935,12 @@
return null;
}
-
@Nullable
- private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+ PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
PackageSetting sharedLibPackage = null;
synchronized (mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
- getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage);
+ getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
if (latestSharedLibraVersionLPr != null) {
sharedLibPackage = mSettings.getPackageLPr(
latestSharedLibraVersionLPr.getPackageName());
@@ -13261,18 +13080,18 @@
cacher.cleanCachedResult(codePath);
}
- private int[] resolveUserIds(int userId) {
+ int[] resolveUserIds(int userId) {
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
- private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
+ void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
return;
}
clearAppDataLeafLIF(pkg, userId, flags);
if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+ clearAppProfilesLIF(pkg);
}
}
@@ -13333,7 +13152,7 @@
}
}
- private void clearAppProfilesLIF(AndroidPackage pkg, int userId) {
+ private void clearAppProfilesLIF(AndroidPackage pkg) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
@@ -13673,7 +13492,7 @@
? PackageManager.DELETE_KEEP_DATA : 0;
deletePackageLIF(pkg.getPackageName(), null, true,
mUserManager.getUserIds(), flags, null,
- true, null);
+ true);
}
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -13697,7 +13516,7 @@
}
@GuardedBy({"mInstallLock", "mLock"})
- private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
+ ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
@@ -13709,106 +13528,9 @@
}
}
- /** The result of a package scan. */
- @VisibleForTesting
- static class ScanResult {
- /** The request that initiated the scan that produced this result. */
- public final ScanRequest request;
- /** Whether or not the package scan was successful */
- public final boolean success;
- /**
- * Whether or not the original PackageSetting needs to be updated with this result on
- * commit.
- */
- public final boolean existingSettingCopied;
- /**
- * The final package settings. This may be the same object passed in
- * the {@link ScanRequest}, but, with modified values.
- */
- @Nullable public final PackageSetting pkgSetting;
- /** ABI code paths that have changed in the package scan */
- @Nullable public final List<String> changedAbiCodePath;
- public final SharedLibraryInfo staticSharedLibraryInfo;
- public final List<SharedLibraryInfo> dynamicSharedLibraryInfos;
- public ScanResult(
- ScanRequest request, boolean success,
- @Nullable PackageSetting pkgSetting,
- @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
- SharedLibraryInfo staticSharedLibraryInfo,
- List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
- this.request = request;
- this.success = success;
- this.pkgSetting = pkgSetting;
- this.changedAbiCodePath = changedAbiCodePath;
- this.existingSettingCopied = existingSettingCopied;
- this.staticSharedLibraryInfo = staticSharedLibraryInfo;
- this.dynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
- }
- }
-
- /** A package to be scanned */
- @VisibleForTesting
- static class ScanRequest {
- /** The parsed package */
- @NonNull public final ParsedPackage parsedPackage;
- /** The package this package replaces */
- @Nullable public final AndroidPackage oldPkg;
- /** Shared user settings, if the package has a shared user */
- @Nullable public final SharedUserSetting sharedUserSetting;
- /**
- * Package settings of the currently installed version.
- * <p><em>IMPORTANT:</em> The contents of this object may be modified
- * during scan.
- */
- @Nullable public final PackageSetting pkgSetting;
- /** A copy of the settings for the currently installed version */
- @Nullable public final PackageSetting oldPkgSetting;
- /** Package settings for the disabled version on the /system partition */
- @Nullable public final PackageSetting disabledPkgSetting;
- /** Package settings for the installed version under its original package name */
- @Nullable public final PackageSetting originalPkgSetting;
- /** The real package name of a renamed application */
- @Nullable public final String realPkgName;
- public final @ParseFlags int parseFlags;
- public final @ScanFlags int scanFlags;
- /** The user for which the package is being scanned */
- @Nullable public final UserHandle user;
- /** Whether or not the platform package is being scanned */
- public final boolean isPlatformPackage;
- /** Override value for package ABI if set during install */
- @Nullable
- public final String cpuAbiOverride;
- public ScanRequest(
- @NonNull ParsedPackage parsedPackage,
- @Nullable SharedUserSetting sharedUserSetting,
- @Nullable AndroidPackage oldPkg,
- @Nullable PackageSetting pkgSetting,
- @Nullable PackageSetting disabledPkgSetting,
- @Nullable PackageSetting originalPkgSetting,
- @Nullable String realPkgName,
- @ParseFlags int parseFlags,
- @ScanFlags int scanFlags,
- boolean isPlatformPackage,
- @Nullable UserHandle user,
- @Nullable String cpuAbiOverride) {
- this.parsedPackage = parsedPackage;
- this.oldPkg = oldPkg;
- this.pkgSetting = pkgSetting;
- this.sharedUserSetting = sharedUserSetting;
- this.oldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
- this.disabledPkgSetting = disabledPkgSetting;
- this.originalPkgSetting = originalPkgSetting;
- this.realPkgName = realPkgName;
- this.parseFlags = parseFlags;
- this.scanFlags = scanFlags;
- this.isPlatformPackage = isPlatformPackage;
- this.user = user;
- this.cpuAbiOverride = cpuAbiOverride;
- }
- }
/**
* Returns the actual scan flags depending upon the state of the other settings.
@@ -13942,7 +13664,7 @@
} else {
isUpdatedSystemApp = disabledPkgSetting != null;
}
- applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
+ applyPolicy(parsedPackage, scanFlags, mPlatformPackage, isUpdatedSystemApp);
assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
@@ -13969,19 +13691,18 @@
}
}
-
/**
* Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering
* the app ID required for reconcile.
* @return {@code true} if a new app ID was registered and will need to be cleaned up on
* failure.
*/
- private boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
+ boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
throws PackageManagerException {
- if (!result.existingSettingCopied) {
+ if (!result.mExistingSettingCopied) {
// THROWS: when we can't allocate a user id. add call to check if there's
// enough space to ensure we won't throw; otherwise, don't modify state
- return mSettings.registerAppIdLPw(result.pkgSetting);
+ return mSettings.registerAppIdLPw(result.mPkgSetting);
}
return false;
}
@@ -13991,11 +13712,11 @@
* {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the
* referenced method returned true.
*/
- private void cleanUpAppIdCreation(@NonNull ScanResult result) {
+ void cleanUpAppIdCreation(@NonNull ScanResult result) {
// iff we've acquired an app ID for a new package setting, remove it so that it can be
// acquired by another request.
- if (result.pkgSetting.appId > 0) {
- mSettings.removeAppIdLPw(result.pkgSetting.appId);
+ if (result.mPkgSetting.appId > 0) {
+ mSettings.removeAppIdLPw(result.mPkgSetting.appId);
}
}
@@ -14007,37 +13728,37 @@
* possible and the system is not left in an inconsistent state.
*/
@GuardedBy({"mLock", "mInstallLock"})
- private AndroidPackage commitReconciledScanResultLocked(
+ AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
- final ScanResult result = reconciledPkg.scanResult;
- final ScanRequest request = result.request;
+ final ScanResult result = reconciledPkg.mScanResult;
+ final ScanRequest request = result.mRequest;
// TODO(b/135203078): Move this even further away
- ParsedPackage parsedPackage = request.parsedPackage;
+ ParsedPackage parsedPackage = request.mParsedPackage;
if ("android".equals(parsedPackage.getPackageName())) {
// TODO(b/135203078): Move this to initial parse
parsedPackage.setVersionCode(mSdkVersion)
.setVersionCodeMajor(0);
}
- final AndroidPackage oldPkg = request.oldPkg;
- final @ParseFlags int parseFlags = request.parseFlags;
- final @ScanFlags int scanFlags = request.scanFlags;
- final PackageSetting oldPkgSetting = request.oldPkgSetting;
- final PackageSetting originalPkgSetting = request.originalPkgSetting;
- final UserHandle user = request.user;
- final String realPkgName = request.realPkgName;
- final List<String> changedAbiCodePath = result.changedAbiCodePath;
+ final AndroidPackage oldPkg = request.mOldPkg;
+ final @ParseFlags int parseFlags = request.mParseFlags;
+ final @ScanFlags int scanFlags = request.mScanFlags;
+ final PackageSetting oldPkgSetting = request.mOldPkgSetting;
+ final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
+ final UserHandle user = request.mUser;
+ final String realPkgName = request.mRealPkgName;
+ final List<String> changedAbiCodePath = result.mChangedAbiCodePath;
final PackageSetting pkgSetting;
- if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
- && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+ if (request.mPkgSetting != null && request.mPkgSetting.sharedUser != null
+ && request.mPkgSetting.sharedUser != result.mPkgSetting.sharedUser) {
// shared user changed, remove from old shared user
- request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+ request.mPkgSetting.sharedUser.removePackage(request.mPkgSetting);
}
- if (result.existingSettingCopied) {
- pkgSetting = request.pkgSetting;
- pkgSetting.updateFrom(result.pkgSetting);
+ if (result.mExistingSettingCopied) {
+ pkgSetting = request.mPkgSetting;
+ pkgSetting.updateFrom(result.mPkgSetting);
} else {
- pkgSetting = result.pkgSetting;
+ pkgSetting = result.mPkgSetting;
if (originalPkgSetting != null) {
mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),
originalPkgSetting.name);
@@ -14049,14 +13770,15 @@
if (pkgSetting.sharedUser != null) {
pkgSetting.sharedUser.addPackage(pkgSetting);
}
- if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) {
+ if (reconciledPkg.mInstallArgs != null
+ && reconciledPkg.mInstallArgs.mForceQueryableOverride) {
pkgSetting.forceQueryableOverride = true;
}
// If this is part of a standard install, set the initiating package name, else rely on
// previous device state.
- if (reconciledPkg.installArgs != null) {
- InstallSource installSource = reconciledPkg.installArgs.installSource;
+ if (reconciledPkg.mInstallArgs != null) {
+ InstallSource installSource = reconciledPkg.mInstallArgs.mInstallSource;
if (installSource.initiatingPackageName != null) {
final PackageSetting ips = mSettings.getPackageLPr(
installSource.initiatingPackageName);
@@ -14083,20 +13805,20 @@
mTransferredPackages.add(pkg.getPackageName());
}
- if (reconciledPkg.collectedSharedLibraryInfos != null) {
+ if (reconciledPkg.mCollectedSharedLibraryInfos != null) {
executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,
- reconciledPkg.collectedSharedLibraryInfos, allUsers);
+ reconciledPkg.mCollectedSharedLibraryInfos, allUsers);
}
final KeySetManagerService ksms = mSettings.getKeySetManagerService();
- if (reconciledPkg.removeAppKeySetData) {
+ if (reconciledPkg.mRemoveAppKeySetData) {
ksms.removeAppKeySetDataLPw(pkg.getPackageName());
}
- if (reconciledPkg.sharedUserSignaturesChanged) {
+ if (reconciledPkg.mSharedUserSignaturesChanged) {
pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
- pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;
+ pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.mSigningDetails;
}
- pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
+ pkgSetting.signatures.mSigningDetails = reconciledPkg.mSigningDetails;
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
@@ -14285,7 +14007,6 @@
}
}
-
/**
* Just scans the package without any side effects.
* <p>Not entirely true at the moment. There is still one side effect -- this
@@ -14306,17 +14027,16 @@
boolean isUnderFactoryTest, long currentTime)
throws PackageManagerException {
final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
- final UserManagerInternal userManager = injector.getUserManagerInternal();
- ParsedPackage parsedPackage = request.parsedPackage;
- PackageSetting pkgSetting = request.pkgSetting;
- final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
- final PackageSetting originalPkgSetting = request.originalPkgSetting;
- final @ParseFlags int parseFlags = request.parseFlags;
- final @ScanFlags int scanFlags = request.scanFlags;
- final String realPkgName = request.realPkgName;
- final SharedUserSetting sharedUserSetting = request.sharedUserSetting;
- final UserHandle user = request.user;
- final boolean isPlatformPackage = request.isPlatformPackage;
+ ParsedPackage parsedPackage = request.mParsedPackage;
+ PackageSetting pkgSetting = request.mPkgSetting;
+ final PackageSetting disabledPkgSetting = request.mDisabledPkgSetting;
+ final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
+ final @ParseFlags int parseFlags = request.mParseFlags;
+ final @ScanFlags int scanFlags = request.mScanFlags;
+ final String realPkgName = request.mRealPkgName;
+ final SharedUserSetting sharedUserSetting = request.mSharedUserSetting;
+ final UserHandle user = request.mUser;
+ final boolean isPlatformPackage = request.mIsPlatformPackage;
List<String> changedAbiCodePath = null;
@@ -14453,7 +14173,7 @@
configurePackageComponents(parsedPackage);
}
- final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
+ final String cpuAbiOverride = deriveAbiOverride(request.mCpuAbiOverride);
final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
final File appLib32InstallDir = getAppLib32InstallDir();
@@ -14694,7 +14414,7 @@
* Implementation detail: This method must NOT have any side effect. It would
* ideally be static, but, it requires locks to read system state.
*/
- private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
+ private static void applyPolicy(ParsedPackage parsedPackage,
final @ScanFlags int scanFlags, AndroidPackage platformPkg,
boolean isUpdatedSystemApp) {
if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
@@ -14751,14 +14471,6 @@
PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp);
}
- private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
- throws PackageManagerException {
- if (object == null) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, message);
- }
- return object;
- }
-
private <T extends ParsedMainComponent>
void assertPackageProcesses(AndroidPackage pkg, List<T> components,
Map<String, ParsedProcess> procs, String compName)
@@ -15143,19 +14855,18 @@
}
@GuardedBy("mLock")
- private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
+ private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
if (nonStaticSharedLibExistsLocked(entry.name)) {
- return false;
+ return;
}
SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
- entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED,
+ entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN,
new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
entry.isNative);
commitSharedLibraryInfoLocked(libraryInfo);
- return true;
}
@GuardedBy("mLock")
@@ -15166,10 +14877,7 @@
private static boolean sharedLibExists(final String name, final long version,
Map<String, WatchedLongSparseArray<SharedLibraryInfo>> librarySource) {
WatchedLongSparseArray<SharedLibraryInfo> versionedLib = librarySource.get(name);
- if (versionedLib != null && versionedLib.indexOfKey(version) >= 0) {
- return true;
- }
- return false;
+ return versionedLib != null && versionedLib.indexOfKey(version) >= 0;
}
@GuardedBy("mLock")
@@ -15314,8 +15022,8 @@
ArrayList<AndroidPackage> clientLibPkgs = null;
// writer
synchronized (mLock) {
- if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
- for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
+ if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) {
+ for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) {
commitSharedLibraryInfoLocked(info);
}
final Map<String, AndroidPackage> combinedSigningDetails =
@@ -15335,8 +15043,8 @@
}
}
}
- if (reconciledPkg.installResult != null) {
- reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
+ if (reconciledPkg.mInstallResult != null) {
+ reconciledPkg.mInstallResult.mLibraryConsumers = clientLibPkgs;
}
if ((scanFlags & SCAN_BOOTING) != 0) {
@@ -15380,7 +15088,7 @@
mComponentResolver.addAllComponents(pkg, chatty);
final boolean isReplace =
- reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
+ reconciledPkg.mPrepareResult != null && reconciledPkg.mPrepareResult.mReplace;
mAppsFilter.addPackage(pkgSetting, isReplace);
mPackageProperty.addAllProperties(pkg);
@@ -15490,7 +15198,7 @@
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
}
- private void killApplication(String pkgName, @AppIdInt int appId,
+ void killApplication(String pkgName, @AppIdInt int appId,
@UserIdInt int userId, String reason) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
@@ -15509,7 +15217,7 @@
}
}
- private void removePackageLI(AndroidPackage pkg, boolean chatty) {
+ void removePackageLI(AndroidPackage pkg, boolean chatty) {
// Remove the parent package setting
PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps != null) {
@@ -15615,10 +15323,10 @@
} else {
resolvedUserIds = userIds;
}
- doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
resolvedUserIds, false, broadcastAllowList, bOptions);
if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
- doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
instantUserIds, true, null, bOptions);
}
} catch (RemoteException ex) {
@@ -15687,7 +15395,7 @@
* the system and applications allowed to see instant applications to receive package
* lifecycle events for instant applications.
*/
- private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
+ private void doSendBroadcast(String action, String pkg, Bundle extras,
int flags, String targetPkg, IIntentReceiver finishedReceiver,
int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList,
@Nullable Bundle bOptions) {
@@ -15728,109 +15436,6 @@
}
}
- /**
- * Check if the external storage media is available. This is true if there
- * is a mounted external storage medium or if the external storage is
- * emulated.
- */
- private boolean isExternalMediaAvailable() {
- return mMediaMounted || Environment.isExternalStorageEmulated();
- }
-
- /**
- * Ensure that the install reason matches what we know about the package installer (e.g. whether
- * it is acting on behalf on an enterprise or the user).
- *
- * Note that the ordering of the conditionals in this method is important. The checks we perform
- * are as follows, in this order:
- *
- * 1) If the install is being performed by a system app, we can trust the app to have set the
- * install reason correctly. Thus, we pass through the install reason unchanged, no matter
- * what it is.
- * 2) If the install is being performed by a device or profile owner app, the install reason
- * should be enterprise policy. However, we cannot be sure that the device or profile owner
- * set the install reason correctly. If the app targets an older SDK version where install
- * reasons did not exist yet, or if the app author simply forgot, the install reason may be
- * unset or wrong. Thus, we force the install reason to be enterprise policy.
- * 3) In all other cases, the install is being performed by a regular app that is neither part
- * of the system nor a device or profile owner. We have no reason to believe that this app is
- * acting on behalf of the enterprise admin. Thus, we check whether the install reason was
- * set to enterprise policy and if so, change it to unknown instead.
- */
- private int fixUpInstallReason(String installerPackageName, int installerUid,
- int installReason) {
- if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
- == PERMISSION_GRANTED) {
- // If the install is being performed by a system app, we trust that app to have set the
- // install reason correctly.
- return installReason;
- }
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(
- UserHandle.getUserId(installerUid));
- if (ownerPackage != null && ownerPackage.equals(installerPackageName)) {
- // If the install is being performed by a device or profile owner, the install
- // reason should be enterprise policy.
- return PackageManager.INSTALL_REASON_POLICY;
- }
-
-
- if (installReason == PackageManager.INSTALL_REASON_POLICY) {
- // If the install is being performed by a regular app (i.e. neither system app nor
- // device or profile owner), we have no reason to believe that the app is acting on
- // behalf of an enterprise. If the app set the install reason to enterprise policy,
- // change it to unknown instead.
- return PackageManager.INSTALL_REASON_UNKNOWN;
- }
-
- // If the install is being performed by a regular app and the install reason was set to any
- // value but enterprise policy, leave the install reason unchanged.
- return installReason;
- }
-
- void installStage(InstallParams params) {
- final Message msg = mHandler.obtainMessage(INIT_COPY);
- params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
-
- mHandler.sendMessage(msg);
- }
-
- void installStage(InstallParams parent, List<InstallParams> children)
- throws PackageManagerException {
- final Message msg = mHandler.obtainMessage(INIT_COPY);
- final MultiPackageInstallParams params =
- new MultiPackageInstallParams(parent, children);
- params.setTraceMethod("installStageMultiPackage")
- .setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
- mHandler.sendMessage(msg);
- }
-
- void verifyStage(VerificationParams params) {
- mHandler.post(()-> {
- params.startCopy();
- });
- }
-
- void verifyStage(VerificationParams parent, List<VerificationParams> children)
- throws PackageManagerException {
- final MultiPackageVerificationParams params =
- new MultiPackageVerificationParams(parent, children);
- mHandler.post(()-> {
- params.startCopy();
- });
- }
-
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId, int dataLoaderType) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -16075,11 +15680,11 @@
private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
- info.removedPackage = packageName;
- info.installerPackageName = pkgSetting.installSource.installerPackageName;
- info.removedUsers = new int[] {userId};
- info.broadcastUsers = new int[] {userId};
- info.uid = UserHandle.getUid(userId, pkgSetting.appId);
+ info.mRemovedPackage = packageName;
+ info.mInstallerPackageName = pkgSetting.installSource.installerPackageName;
+ info.mRemovedUsers = new int[] {userId};
+ info.mBroadcastUsers = new int[] {userId};
+ info.mUid = UserHandle.getUid(userId, pkgSetting.appId);
info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/);
}
@@ -16279,17 +15884,17 @@
updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
// start async restore with no post-install since we finish install here
- PackageInstalledInfo res =
- createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
- res.pkg = pkgSetting.pkg;
- res.newUsers = new int[]{ userId };
+ PackageInstalledInfo res = new PackageInstalledInfo(
+ PackageManager.INSTALL_SUCCEEDED);
+ res.mPkg = pkgSetting.pkg;
+ res.mNewUsers = new int[]{ userId };
PostInstallData postInstallData =
new PostInstallData(null, res, () -> {
restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
- pkgSetting.getInstallReason(userId), userId);
+ userId);
if (intentSender != null) {
- onRestoreComplete(res.returnCode, mContext, intentSender);
+ onRestoreComplete(res.mReturnCode, mContext, intentSender);
}
});
restoreAndPostInstall(userId, res, postInstallData);
@@ -16564,7 +16169,7 @@
} else {
intentExtras = null;
}
- doSendBroadcast(am, action, null, intentExtras,
+ doSendBroadcast(action, null, intentExtras,
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
targetUserIds, false, null, null);
}
@@ -16864,7 +16469,7 @@
}
}
- private void broadcastPackageVerified(int verificationId, Uri packageUri,
+ void broadcastPackageVerified(int verificationId, Uri packageUri,
int verificationCode, @Nullable String rootHashString, int dataLoaderType,
UserHandle user) {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
@@ -16881,101 +16486,6 @@
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
}
- private ComponentName matchComponentForVerifier(String packageName,
- List<ResolveInfo> receivers) {
- ActivityInfo targetReceiver = null;
-
- final int NR = receivers.size();
- for (int i = 0; i < NR; i++) {
- final ResolveInfo info = receivers.get(i);
- if (info.activityInfo == null) {
- continue;
- }
-
- if (packageName.equals(info.activityInfo.packageName)) {
- targetReceiver = info.activityInfo;
- break;
- }
- }
-
- if (targetReceiver == null) {
- return null;
- }
-
- return new ComponentName(targetReceiver.packageName, targetReceiver.name);
- }
-
- private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
- List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
- if (pkgInfo.verifiers.length == 0) {
- return null;
- }
-
- final int N = pkgInfo.verifiers.length;
- final List<ComponentName> sufficientVerifiers = new ArrayList<>(N + 1);
- for (int i = 0; i < N; i++) {
- final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
-
- final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
- receivers);
- if (comp == null) {
- continue;
- }
-
- final int verifierUid = getUidForVerifier(verifierInfo);
- if (verifierUid == -1) {
- continue;
- }
-
- if (DEBUG_VERIFY) {
- Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
- + " with the correct signature");
- }
- sufficientVerifiers.add(comp);
- verificationState.addSufficientVerifier(verifierUid);
- }
-
- return sufficientVerifiers;
- }
-
- private int getUidForVerifier(VerifierInfo verifierInfo) {
- synchronized (mLock) {
- final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
- if (pkg == null) {
- return -1;
- } else if (pkg.getSigningDetails().getSignatures().length != 1) {
- Slog.i(TAG, "Verifier package " + verifierInfo.packageName
- + " has more than one signature; ignoring");
- return -1;
- }
-
- /*
- * If the public key of the package's signature does not match
- * our expected public key, then this is a different package and
- * we should skip.
- */
-
- final byte[] expectedPublicKey;
- try {
- final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
- final PublicKey publicKey = verifierSig.getPublicKey();
- expectedPublicKey = publicKey.getEncoded();
- } catch (CertificateException e) {
- return -1;
- }
-
- final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
-
- if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
- Slog.i(TAG, "Verifier package " + verifierInfo.packageName
- + " does not have the expected public key; ignoring");
- return -1;
- }
-
- return pkg.getUid();
- }
- }
-
private void setEnableRollbackCode(int token, int enableRollbackCode) {
final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
msg.arg1 = token;
@@ -17002,7 +16512,7 @@
*
* @return verification timeout in milliseconds
*/
- private long getVerificationTimeout() {
+ long getVerificationTimeout() {
long timeout = Global.getLong(mContext.getContentResolver(),
Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
// The setting can be used to increase the timeout but not decrease it, since that is
@@ -17010,18 +16520,6 @@
return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
}
- /**
- * Get the integrity verification timeout.
- *
- * @return verification timeout in milliseconds
- */
- private long getIntegrityVerificationTimeout() {
- long timeout = Global.getLong(mContext.getContentResolver(),
- Global.APP_INTEGRITY_VERIFICATION_TIMEOUT, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
- // The setting can be used to increase the timeout but not decrease it, since that is
- // equivalent to disabling the integrity component.
- return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
- }
/**
* Get the default verification agent response code.
@@ -17046,65 +16544,6 @@
return PackageManager.VERIFICATION_REJECT;
}
- /**
- * Check whether or not package verification has been enabled.
- *
- * @return true if verification should be performed
- */
- private boolean isVerificationEnabled(
- PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
- if (!DEFAULT_VERIFY_ENABLE) {
- return false;
- }
-
- // Check if installing from ADB
- if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
- if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
- return true;
- }
- // Check if the developer wants to skip verification for ADB installs
- if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
- synchronized (mLock) {
- if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
- // Always verify fresh install
- return true;
- }
- }
- // Only skip when apk is debuggable
- return !pkgInfoLite.debuggable;
- }
- return Global.getInt(mContext.getContentResolver(),
- Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
- }
-
- // only when not installed from ADB, skip verification for instant apps when
- // the installer and verifier are the same.
- if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- if (mInstantAppInstallerActivity != null
- && mInstantAppInstallerActivity.packageName.equals(
- mRequiredVerifierPackage)) {
- try {
- mInjector.getSystemService(AppOpsManager.class)
- .checkPackage(installerUid, mRequiredVerifierPackage);
- if (DEBUG_VERIFY) {
- Slog.i(TAG, "disable verification for instant app");
- }
- return false;
- } catch (SecurityException ignore) { }
- }
- }
- return true;
- }
-
- /**
- * Check whether or not integrity verification has been enabled.
- */
- private boolean isIntegrityVerificationEnabled() {
- // We are not exposing this as a user-configurable setting because we don't want to provide
- // an easy way to get around the integrity check.
- return DEFAULT_INTEGRITY_VERIFY_ENABLE;
- }
-
@Deprecated
@Override
public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
@@ -17317,124 +16756,18 @@
}
}
- // Queue up an async operation since the package installation may take a little while.
- private void processInstallRequestsAsync(boolean success,
- List<InstallRequest> installRequests) {
- mHandler.post(() -> {
- List<InstallRequest> apexInstallRequests = new ArrayList<>();
- List<InstallRequest> apkInstallRequests = new ArrayList<>();
- for (InstallRequest request : installRequests) {
- if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) {
- apexInstallRequests.add(request);
- } else {
- apkInstallRequests.add(request);
- }
- }
- // Note: supporting multi package install of both APEXes and APKs might requir some
- // thinking to ensure atomicity of the install.
- if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
- // This should've been caught at the validation step, but for some reason wasn't.
- throw new IllegalStateException(
- "Attempted to do a multi package install of both APEXes and APKs");
- }
- if (!apexInstallRequests.isEmpty()) {
- if (success) {
- // Since installApexPackages requires talking to external service (apexd), we
- // schedule to run it async. Once it finishes, it will resume the install.
- Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
- "installApexPackages");
- t.start();
- } else {
- // Non-staged APEX installation failed somewhere before
- // processInstallRequestAsync. In that case just notify the observer about the
- // failure.
- InstallRequest request = apexInstallRequests.get(0);
- notifyInstallObserver(request.installResult, request.args.observer);
- }
- return;
- }
- if (success) {
- for (InstallRequest request : apkInstallRequests) {
- request.args.doPreInstall(request.installResult.returnCode);
- }
- synchronized (mInstallLock) {
- installPackagesTracedLI(apkInstallRequests);
- }
- for (InstallRequest request : apkInstallRequests) {
- request.args.doPostInstall(
- request.installResult.returnCode, request.installResult.uid);
- }
- }
- for (InstallRequest request : apkInstallRequests) {
- restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
- new PostInstallData(request.args, request.installResult, null));
- }
- });
- }
-
- private void installApexPackagesTraced(List<InstallRequest> requests) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages");
- installApexPackages(requests);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- private void installApexPackages(List<InstallRequest> requests) {
- if (requests.isEmpty()) {
- return;
- }
- if (requests.size() != 1) {
- throw new IllegalStateException(
- "Only a non-staged install of a single APEX is supported");
- }
- InstallRequest request = requests.get(0);
- try {
- // Should directory scanning logic be moved to ApexManager for better test coverage?
- final File dir = request.args.origin.resolvedFile;
- final File[] apexes = dir.listFiles();
- if (apexes == null) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- dir.getAbsolutePath() + " is not a directory");
- }
- if (apexes.length != 1) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Expected exactly one .apex file under " + dir.getAbsolutePath()
- + " got: " + apexes.length);
- }
- try (PackageParser2 packageParser = mInjector.getScanningPackageParser()) {
- mApexManager.installPackage(apexes[0], packageParser);
- }
- } catch (PackageManagerException e) {
- request.installResult.setError("APEX installation failed", e);
- }
- invalidatePackageInfoCache();
- notifyInstallObserver(request.installResult, request.args.observer);
- }
-
- private PackageInstalledInfo createPackageInstalledInfo(
- int currentStatus) {
- PackageInstalledInfo res = new PackageInstalledInfo();
- res.setReturnCode(currentStatus);
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = null;
- return res;
- }
-
/** @param data Post-install is performed only if this is non-null. */
- private void restoreAndPostInstall(
+ void restoreAndPostInstall(
int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
if (DEBUG_INSTALL) {
- Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
+ Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.mPkg);
}
// A restore should be requested at this point if (a) the install
// succeeded, (b) the operation is not an update.
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
- boolean doRestore = !update && res.pkg != null;
+ final boolean update = res.mRemovedInfo != null
+ && res.mRemovedInfo.mRemovedPackage != null;
+ boolean doRestore = !update && res.mPkg != null;
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
@@ -17450,13 +16783,13 @@
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+ if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
- if (res.freezer != null) {
- res.freezer.close();
+ if (res.mFreezer != null) {
+ res.mFreezer.close();
}
doRestore = performBackupManagerRestore(userId, token, res);
}
@@ -17466,7 +16799,7 @@
// need to be snapshotted or restored for the package.
//
// TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+ if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
doRestore = performRollbackManagerRestore(userId, token, res, data);
}
@@ -17502,7 +16835,7 @@
try {
if (bm.isUserReadyForBackup(userId)) {
bm.restoreAtInstallForUser(
- userId, res.pkg.getPackageName(), token);
+ userId, res.mPkg.getPackageName(), token);
} else {
Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
+ "didn't take place.");
@@ -17529,7 +16862,7 @@
PostInstallData data) {
RollbackManagerInternal rm = mInjector.getLocalService(RollbackManagerInternal.class);
- final String packageName = res.pkg.getPackageName();
+ final String packageName = res.mPkg.getPackageName();
final int[] allUsers = mUserManager.getUserIds();
final int[] installedUsers;
@@ -17549,11 +16882,11 @@
}
boolean doSnapshotOrRestore = data != null && data.args != null
- && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
- || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
+ && ((data.args.mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
+ || (data.args.mInstallFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
if (ps != null && doSnapshotOrRestore) {
- final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps);
+ final String seInfo = AndroidPackageUtils.getSeInfo(res.mPkg, ps);
rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers),
appId, ceDataInode, seInfo, token);
return true;
@@ -17581,13 +16914,13 @@
mHandler.post(() -> {
for (int i = 0; i < mRunningInstalls.size(); i++) {
final PostInstallData data = mRunningInstalls.valueAt(i);
- if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ if (data.res.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
- if (packageName.equals(data.res.pkg.getPackageName())) {
+ if (packageName.equals(data.res.mPkg.getPackageName())) {
// right package; but is it for the right user?
- for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
- if (userId == data.res.newUsers[uIndex]) {
+ for (int uIndex = 0; uIndex < data.res.mNewUsers.length; uIndex++) {
+ if (userId == data.res.mNewUsers[uIndex]) {
if (DEBUG_BACKUP) {
Slog.i(TAG, "Package " + packageName
+ " being restored so deferring FIRST_LAUNCH");
@@ -17614,1382 +16947,12 @@
installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
}
- private abstract class HandlerParams {
- /** User handle for the user requesting the information or installation. */
- private final UserHandle mUser;
- String traceMethod;
- int traceCookie;
-
- HandlerParams(UserHandle user) {
- mUser = user;
- }
-
- UserHandle getUser() {
- return mUser;
- }
-
- HandlerParams setTraceMethod(String traceMethod) {
- this.traceMethod = traceMethod;
- return this;
- }
-
- HandlerParams setTraceCookie(int traceCookie) {
- this.traceCookie = traceCookie;
- return this;
- }
-
- final void startCopy() {
- if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
- handleStartCopy();
- handleReturnCode();
- }
-
- abstract void handleStartCopy();
- abstract void handleReturnCode();
- }
-
- static class OriginInfo {
- /**
- * Location where install is coming from, before it has been
- * copied/renamed into place. This could be a single monolithic APK
- * file, or a cluster directory. This location may be untrusted.
- */
- final File file;
-
- /**
- * Flag indicating that {@link #file} has already been staged, meaning downstream users
- * don't need to defensively copy the contents.
- */
- final boolean staged;
-
- /**
- * Flag indicating that {@link #file} is an already installed app that is being moved.
- */
- final boolean existing;
-
- final String resolvedPath;
- final File resolvedFile;
-
- static OriginInfo fromNothing() {
- return new OriginInfo(null, false, false);
- }
-
- static OriginInfo fromUntrustedFile(File file) {
- return new OriginInfo(file, false, false);
- }
-
- static OriginInfo fromExistingFile(File file) {
- return new OriginInfo(file, false, true);
- }
-
- static OriginInfo fromStagedFile(File file) {
- return new OriginInfo(file, true, false);
- }
-
- private OriginInfo(File file, boolean staged, boolean existing) {
- this.file = file;
- this.staged = staged;
- this.existing = existing;
-
- if (file != null) {
- resolvedPath = file.getAbsolutePath();
- resolvedFile = file;
- } else {
- resolvedPath = null;
- resolvedFile = null;
- }
- }
- }
-
- static class MoveInfo {
- final int moveId;
- final String fromUuid;
- final String toUuid;
- final String packageName;
- final int appId;
- final String seinfo;
- final int targetSdkVersion;
- final String fromCodePath;
-
- public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
- int appId, String seinfo, int targetSdkVersion,
- String fromCodePath) {
- this.moveId = moveId;
- this.fromUuid = fromUuid;
- this.toUuid = toUuid;
- this.packageName = packageName;
- this.appId = appId;
- this.seinfo = seinfo;
- this.targetSdkVersion = targetSdkVersion;
- this.fromCodePath = fromCodePath;
- }
- }
-
- static class VerificationInfo {
- /** A constant used to indicate that a uid value is not present. */
- public static final int NO_UID = -1;
-
- /** URI referencing where the package was downloaded from. */
- final Uri originatingUri;
-
- /** HTTP referrer URI associated with the originatingURI. */
- final Uri referrer;
-
- /** UID of the application that the install request originated from. */
- final int originatingUid;
-
- /** UID of application requesting the install */
- final int installerUid;
-
- VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
- this.originatingUri = originatingUri;
- this.referrer = referrer;
- this.originatingUid = originatingUid;
- this.installerUid = installerUid;
- }
- }
-
- /**
- * Container for a multi-package install which refers to all install sessions and args being
- * committed together.
- */
- class MultiPackageInstallParams extends HandlerParams {
- private final List<InstallParams> mChildParams;
- private final Map<InstallArgs, Integer> mCurrentState;
-
- MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
- throws PackageManagerException {
- super(parent.getUser());
- if (childParams.size() == 0) {
- throw new PackageManagerException("No child sessions found!");
- }
- mChildParams = childParams;
- for (int i = 0; i < childParams.size(); i++) {
- final InstallParams childParam = childParams.get(i);
- childParam.mParentInstallParams = this;
- }
- this.mCurrentState = new ArrayMap<>(mChildParams.size());
- }
-
- @Override
- void handleStartCopy() {
- for (InstallParams params : mChildParams) {
- params.handleStartCopy();
- }
- }
-
- @Override
- void handleReturnCode() {
- for (InstallParams params : mChildParams) {
- params.handleReturnCode();
- }
- }
-
- void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
- mCurrentState.put(args, currentStatus);
- if (mCurrentState.size() != mChildParams.size()) {
- return;
- }
- int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mCurrentState.values()) {
- if (status == PackageManager.INSTALL_UNKNOWN) {
- return;
- } else if (status != PackageManager.INSTALL_SUCCEEDED) {
- completeStatus = status;
- break;
- }
- }
- final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
- for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
- installRequests.add(new InstallRequest(entry.getKey(),
- createPackageInstalledInfo(completeStatus)));
- }
- processInstallRequestsAsync(
- completeStatus == PackageManager.INSTALL_SUCCEEDED,
- installRequests);
- }
- }
-
- class InstallParams extends HandlerParams {
- final OriginInfo origin;
- final MoveInfo move;
- final IPackageInstallObserver2 observer;
- int installFlags;
- @NonNull final InstallSource installSource;
- final String volumeUuid;
- int mRet;
- final String packageAbiOverride;
- final String[] grantedRuntimePermissions;
- final List<String> whitelistedRestrictedPermissions;
- final int autoRevokePermissionsMode;
- final SigningDetails signingDetails;
- final int installReason;
- final int mInstallScenario;
- @Nullable MultiPackageInstallParams mParentInstallParams;
- final boolean forceQueryableOverride;
- final int mDataLoaderType;
- final long requiredInstalledVersionCode;
- final PackageLite mPackageLite;
-
- InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
- int installFlags, InstallSource installSource, String volumeUuid,
- UserHandle user, String packageAbiOverride, PackageLite packageLite) {
- super(user);
- this.origin = origin;
- this.move = move;
- this.observer = observer;
- this.installFlags = installFlags;
- this.installSource = Preconditions.checkNotNull(installSource);
- this.volumeUuid = volumeUuid;
- this.packageAbiOverride = packageAbiOverride;
-
- this.grantedRuntimePermissions = null;
- this.whitelistedRestrictedPermissions = null;
- this.autoRevokePermissionsMode = MODE_DEFAULT;
- this.signingDetails = SigningDetails.UNKNOWN;
- this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
- this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
- this.forceQueryableOverride = false;
- this.mDataLoaderType = DataLoaderType.NONE;
- this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
- this.mPackageLite = packageLite;
- }
-
- InstallParams(File stagedDir, IPackageInstallObserver2 observer,
- PackageInstaller.SessionParams sessionParams, InstallSource installSource,
- UserHandle user, SigningDetails signingDetails, int installerUid,
- PackageLite packageLite) {
- super(user);
- origin = OriginInfo.fromStagedFile(stagedDir);
- move = null;
- installReason = fixUpInstallReason(
- installSource.installerPackageName, installerUid, sessionParams.installReason);
- mInstallScenario = sessionParams.installScenario;
- this.observer = observer;
- installFlags = sessionParams.installFlags;
- this.installSource = installSource;
- volumeUuid = sessionParams.volumeUuid;
- packageAbiOverride = sessionParams.abiOverride;
- grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
- whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
- autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
- this.signingDetails = signingDetails;
- forceQueryableOverride = sessionParams.forceQueryableOverride;
- mDataLoaderType = (sessionParams.dataLoaderParams != null)
- ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
- requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
- mPackageLite = packageLite;
- }
-
- @Override
- public String toString() {
- return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
- + " file=" + origin.file + "}";
- }
-
- private int installLocationPolicy(PackageInfoLite pkgLite) {
- String packageName = pkgLite.packageName;
- int installLocation = pkgLite.installLocation;
- // reader
- synchronized (mLock) {
- // Currently installed package which the new package is attempting to replace or
- // null if no such package is installed.
- AndroidPackage installedPkg = mPackages.get(packageName);
-
- if (installedPkg != null) {
- if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
- // Check for updated system application.
- if (installedPkg.isSystem()) {
- return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- } else {
- // If current upgrade specifies particular preference
- if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
- // Application explicitly specified internal.
- return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
- // App explictly prefers external. Let policy decide
- } else {
- // Prefer previous location
- if (installedPkg.isExternalStorage()) {
- return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
- }
- return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- }
- }
- } else {
- // Invalid install. Return error code
- return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
- }
- }
- }
- return pkgLite.recommendedInstallLocation;
- }
-
- /**
- * Override install location based on default policy if needed.
- *
- * Only {@link #installFlags} may mutate in this method.
- *
- * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in
- * {@link #installFlags}
- */
- private int overrideInstallLocation(PackageInfoLite pkgLite) {
- final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- if (DEBUG_INSTANT && ephemeral) {
- Slog.v(TAG, "pkgLite for install: " + pkgLite);
- }
-
- if (origin.staged) {
- // If we're already staged, we've firmly committed to an install location
- if (origin.file != null) {
- installFlags |= PackageManager.INSTALL_INTERNAL;
- } else {
- throw new IllegalStateException("Invalid stage location");
- }
- } else if (pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- /*
- * If we are not staged and have too little free space, try to free cache
- * before giving up.
- */
- // TODO: focus freeing disk space on the target device
- final StorageManager storage = StorageManager.from(mContext);
- final long lowThreshold = storage.getStorageLowBytes(
- Environment.getDataDirectory());
-
- final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
- origin.resolvedPath, packageAbiOverride);
- if (sizeBytes >= 0) {
- try {
- mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
- pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
- mPackageLite, origin.resolvedPath, installFlags,
- packageAbiOverride);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to free cache", e);
- }
- }
-
- /*
- * The cache free must have deleted the file we downloaded to install.
- *
- * TODO: fix the "freeCache" call to not delete the file we care about.
- */
- if (pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
- pkgLite.recommendedInstallLocation
- = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
- }
- }
-
- int ret = INSTALL_SUCCEEDED;
- int loc = pkgLite.recommendedInstallLocation;
- if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
- ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
- ret = PackageManager.INSTALL_FAILED_INVALID_APK;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
- ret = PackageManager.INSTALL_FAILED_INVALID_URI;
- } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
- ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
- } else {
- // Override with defaults if needed.
- loc = installLocationPolicy(pkgLite);
-
- final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
-
- if (!onInt) {
- // Override install location with flags
- if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- // Set the flag to install on external media.
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
- } else {
- // Make sure the flag for installing on external
- // media is unset
- installFlags |= PackageManager.INSTALL_INTERNAL;
- }
- }
- }
- return ret;
- }
-
- /*
- * Invoke remote method to get package information and install
- * location values. Override install location based on default
- * policy if needed and then create install arguments based
- * on the install location.
- */
- public void handleStartCopy() {
- if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
- mRet = INSTALL_SUCCEEDED;
- return;
- }
- PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
- mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
-
- // For staged session, there is a delay between its verification and install. Device
- // 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(
- pkgLite, requiredInstalledVersionCode, installFlags);
- if (mRet != INSTALL_SUCCEEDED) {
- return;
- }
- }
-
- mRet = overrideInstallLocation(pkgLite);
- }
-
- @Override
- void handleReturnCode() {
- processPendingInstall();
- }
-
- private void processPendingInstall() {
- InstallArgs args = createInstallArgs(this);
- if (mRet == PackageManager.INSTALL_SUCCEEDED) {
- mRet = args.copyApk();
- }
- if (mRet == PackageManager.INSTALL_SUCCEEDED) {
- F2fsUtils.releaseCompressedBlocks(
- mContext.getContentResolver(), new File(args.getCodePath()));
- }
- if (mParentInstallParams != null) {
- mParentInstallParams.tryProcessInstallRequest(args, mRet);
- } else {
- PackageInstalledInfo res = createPackageInstalledInfo(mRet);
- processInstallRequestsAsync(
- res.returnCode == PackageManager.INSTALL_SUCCEEDED,
- Collections.singletonList(new InstallRequest(args, res)));
- }
- }
- }
-
- /**
- * Container for a multi-package install which refers to all install sessions and args being
- * committed together.
- */
- class MultiPackageVerificationParams extends HandlerParams {
- private final IPackageInstallObserver2 mObserver;
- private final List<VerificationParams> mChildParams;
- private final Map<VerificationParams, Integer> mVerificationState;
-
- MultiPackageVerificationParams(
- VerificationParams parent,
- List<VerificationParams> children)
- throws PackageManagerException {
- super(parent.getUser());
- if (children.size() == 0) {
- throw new PackageManagerException("No child sessions found!");
- }
- mChildParams = children;
- // Provide every child with reference to this object as parent
- for (int i = 0; i < children.size(); i++) {
- final VerificationParams childParams = children.get(i);
- childParams.mParentVerificationParams = this;
- }
- this.mVerificationState = new ArrayMap<>(mChildParams.size());
- mObserver = parent.observer;
- }
-
- @Override
- void handleStartCopy() {
- for (VerificationParams params : mChildParams) {
- params.handleStartCopy();
- }
- }
-
- @Override
- void handleReturnCode() {
- for (VerificationParams params : mChildParams) {
- params.handleReturnCode();
- }
- }
-
- void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
- mVerificationState.put(child, currentStatus);
- if (mVerificationState.size() != mChildParams.size()) {
- return;
- }
- int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mVerificationState.values()) {
- if (status == PackageManager.INSTALL_UNKNOWN) {
- return;
- } else if (status != PackageManager.INSTALL_SUCCEEDED) {
- completeStatus = status;
- break;
- }
- }
- try {
- mObserver.onPackageInstalled(null, completeStatus,
- "Package Verification Result", new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
- }
-
- class VerificationParams extends HandlerParams {
- final OriginInfo origin;
- final IPackageInstallObserver2 observer;
- final int installFlags;
- @NonNull final InstallSource installSource;
- final String packageAbiOverride;
- final VerificationInfo verificationInfo;
- final SigningDetails signingDetails;
- @Nullable MultiPackageVerificationParams mParentVerificationParams;
- final long requiredInstalledVersionCode;
- final int mDataLoaderType;
- final int mSessionId;
-
- private boolean mWaitForVerificationToComplete;
- private boolean mWaitForIntegrityVerificationToComplete;
- private boolean mWaitForEnableRollbackToComplete;
- private int mRet;
-
- final PackageLite mPackageLite;
-
- VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
- PackageInstaller.SessionParams sessionParams, InstallSource installSource,
- int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite) {
- super(user);
- origin = OriginInfo.fromStagedFile(stagedDir);
- this.observer = observer;
- installFlags = sessionParams.installFlags;
- this.installSource = installSource;
- packageAbiOverride = sessionParams.abiOverride;
- verificationInfo = new VerificationInfo(
- sessionParams.originatingUri,
- sessionParams.referrerUri,
- sessionParams.originatingUid,
- installerUid
- );
- this.signingDetails = signingDetails;
- requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
- mDataLoaderType = (sessionParams.dataLoaderParams != null)
- ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
- mSessionId = sessionId;
- mPackageLite = lite;
- }
-
- @Override
- public String toString() {
- return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
- + " file=" + origin.file + "}";
- }
-
- public void handleStartCopy() {
- PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
- mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
-
- mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
- if (mRet != INSTALL_SUCCEEDED) {
- return;
- }
-
- // Perform package verification and enable rollback (unless we are simply moving the
- // package).
- if (!origin.existing) {
- if ((installFlags & PackageManager.INSTALL_APEX) == 0) {
- // TODO(b/182426975): treat APEX as APK when APK verification is concerned
- sendApkVerificationRequest(pkgLite);
- }
- if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
- sendEnableRollbackRequest();
- }
- }
- }
-
- void sendApkVerificationRequest(PackageInfoLite pkgLite) {
- final int verificationId = mPendingVerificationToken++;
-
- PackageVerificationState verificationState =
- new PackageVerificationState(this);
- mPendingVerification.append(verificationId, verificationState);
-
- sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
- mRet = sendPackageVerificationRequest(
- verificationId, pkgLite, verificationState);
-
- // If both verifications are skipped, we should remove the state.
- if (verificationState.areAllVerificationsComplete()) {
- mPendingVerification.remove(verificationId);
- }
- }
-
- void sendEnableRollbackRequest() {
- final int enableRollbackToken = mPendingEnableRollbackToken++;
- Trace.asyncTraceBegin(
- TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
- mPendingEnableRollback.append(enableRollbackToken, this);
-
- Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
- enableRollbackIntent.putExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
- enableRollbackToken);
- enableRollbackIntent.putExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
- mSessionId);
- enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
- enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- // Allow the broadcast to be sent before boot complete.
- // This is needed when committing the apk part of a staged
- // session in early boot. The rollback manager registers
- // its receiver early enough during the boot process that
- // it will not miss the broadcast.
- enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
- mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
- android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
-
- mWaitForEnableRollbackToComplete = true;
-
- // the duration to wait for rollback to be enabled, in millis
- long rollbackTimeout = DeviceConfig.getLong(
- DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
- if (rollbackTimeout < 0) {
- rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
- }
- final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
- msg.arg1 = enableRollbackToken;
- msg.arg2 = mSessionId;
- mHandler.sendMessageDelayed(msg, rollbackTimeout);
- }
-
- /**
- * Send a request to check the integrity of the package.
- */
- void sendIntegrityVerificationRequest(
- int verificationId,
- PackageInfoLite pkgLite,
- PackageVerificationState verificationState) {
- if (!isIntegrityVerificationEnabled()) {
- // Consider the integrity check as passed.
- verificationState.setIntegrityVerificationResult(
- PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
- return;
- }
-
- final Intent integrityVerification =
- new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-
- integrityVerification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
- PACKAGE_MIME_TYPE);
-
- final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND;
- integrityVerification.addFlags(flags);
-
- integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
- integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
- integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
- integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
- populateInstallerExtras(integrityVerification);
-
- // send to integrity component only.
- integrityVerification.setPackage("android");
-
- final BroadcastOptions options = BroadcastOptions.makeBasic();
-
- mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
- /* receiverPermission= */ null,
- /* appOp= */ AppOpsManager.OP_NONE,
- /* options= */ options.toBundle(),
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final Message msg =
- mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
- msg.arg1 = verificationId;
- mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
- }
- }, /* scheduler= */ null,
- /* initialCode= */ 0,
- /* initialData= */ null,
- /* initialExtras= */ null);
-
- Trace.asyncTraceBegin(
- TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
-
- // stop the copy until verification succeeds.
- mWaitForIntegrityVerificationToComplete = true;
- }
-
- /**
- * Send a request to verifier(s) to verify the package if necessary, and return
- * {@link PackageManager#INSTALL_SUCCEEDED} if succeeded.
- */
- int 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
- UserHandle verifierUser = getUser();
- if (verifierUser == UserHandle.ALL) {
- verifierUser = UserHandle.SYSTEM;
- }
-
- /*
- * Determine if we have any installed package verifiers. If we
- * do, then we'll defer to them to verify the packages.
- */
- final int requiredUid = mRequiredVerifierPackage == null ? -1
- : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
- verifierUser.getIdentifier());
- verificationState.setRequiredVerifierUid(requiredUid);
- final int installerUid =
- verificationInfo == null ? -1 : verificationInfo.installerUid;
- final boolean isVerificationEnabled = isVerificationEnabled(
- pkgLite, verifierUser.getIdentifier(), installFlags, installerUid);
- final boolean isV4Signed =
- (signingDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
- final boolean isIncrementalInstall =
- (mDataLoaderType == DataLoaderType.INCREMENTAL);
- // NOTE: We purposefully skip verification for only incremental installs when there's
- // a v4 signature block. Otherwise, proceed with verification as usual.
- if (!origin.existing
- && isVerificationEnabled
- && (!isIncrementalInstall || !isV4Signed)) {
- final Intent verification = new Intent(
- Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
- PACKAGE_MIME_TYPE);
- verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- // Query all live verifiers based on current user state
- final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
- PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
- false /*allowDynamicSplits*/);
-
- if (DEBUG_VERIFY) {
- Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
- + verification.toString() + " with " + pkgLite.verifiers.length
- + " optional verifiers");
- }
-
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
-
- verification.putExtra(
- PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, installFlags);
-
- verification.putExtra(
- PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
-
- verification.putExtra(
- PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
-
- verification.putExtra(
- PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
- pkgLite.getLongVersionCode());
-
- populateInstallerExtras(verification);
-
- final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
- receivers, verificationState);
-
- DeviceIdleInternal idleController =
- mInjector.getLocalService(DeviceIdleInternal.class);
- final long idleDuration = getVerificationTimeout();
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setTemporaryAppAllowlist(idleDuration,
- TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- REASON_PACKAGE_VERIFIER, "");
-
- /*
- * If any sufficient verifiers were listed in the package
- * manifest, attempt to ask them.
- */
- 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;
- } else {
- for (int i = 0; i < n; i++) {
- final ComponentName verifierComponent = sufficientVerifiers.get(i);
- idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
- verifierComponent.getPackageName(), idleDuration,
- verifierUser.getIdentifier(), false,
- REASON_PACKAGE_VERIFIER,"package verifier");
-
- final Intent sufficientIntent = new Intent(verification);
- sufficientIntent.setComponent(verifierComponent);
- mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
- /* receiverPermission= */ null,
- options.toBundle());
- }
- }
- }
-
- if (mRequiredVerifierPackage != null) {
- final ComponentName requiredVerifierComponent = matchComponentForVerifier(
- mRequiredVerifierPackage, receivers);
- /*
- * Send the intent to the required verification agent,
- * but only start the verification timeout after the
- * target BroadcastReceivers have run.
- */
- verification.setComponent(requiredVerifierComponent);
- idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
- mRequiredVerifierPackage, idleDuration,
- verifierUser.getIdentifier(), false,
- REASON_PACKAGE_VERIFIER, "package verifier");
- mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- /* appOp= */ AppOpsManager.OP_NONE,
- /* options= */ options.toBundle(),
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final Message msg = mHandler
- .obtainMessage(CHECK_PENDING_VERIFICATION);
- msg.arg1 = verificationId;
- mHandler.sendMessageDelayed(msg, getVerificationTimeout());
- }
- }, null, 0, null, null);
-
- Trace.asyncTraceBegin(
- TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
- /*
- * We don't want the copy to proceed until verification
- * succeeds.
- */
- mWaitForVerificationToComplete = true;
- }
- } else {
- verificationState.setVerifierResponse(
- requiredUid, PackageManager.VERIFICATION_ALLOW);
- }
- return ret;
- }
-
- void populateInstallerExtras(Intent intent) {
- intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
- installSource.initiatingPackageName);
-
- if (verificationInfo != null) {
- if (verificationInfo.originatingUri != null) {
- intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
- verificationInfo.originatingUri);
- }
- if (verificationInfo.referrer != null) {
- intent.putExtra(Intent.EXTRA_REFERRER,
- verificationInfo.referrer);
- }
- if (verificationInfo.originatingUid >= 0) {
- intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
- verificationInfo.originatingUid);
- }
- if (verificationInfo.installerUid >= 0) {
- intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
- verificationInfo.installerUid);
- }
- }
- }
-
- void setReturnCode(int ret) {
- 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;
- }
- }
-
- void handleVerificationFinished() {
- mWaitForVerificationToComplete = false;
- handleReturnCode();
- }
-
- void handleIntegrityVerificationFinished() {
- mWaitForIntegrityVerificationToComplete = false;
- handleReturnCode();
- }
-
-
- void handleRollbackEnabled() {
- // TODO(ruhler) b/112431924: Consider halting the install if we
- // couldn't enable rollback.
- mWaitForEnableRollbackToComplete = false;
- handleReturnCode();
- }
-
- @Override
- void handleReturnCode() {
- if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
- || mWaitForEnableRollbackToComplete) {
- return;
- }
- sendVerificationCompleteNotification();
- }
-
- private void sendVerificationCompleteNotification() {
- if (mParentVerificationParams != null) {
- mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
- } else {
- try {
- observer.onPackageInstalled(null, mRet, "Package Verification Result",
- new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
- }
- }
-
- private InstallArgs createInstallArgs(InstallParams params) {
- if (params.move != null) {
- return new MoveInstallArgs(params);
- } else {
- return new FileInstallArgs(params);
- }
- }
-
/**
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
- private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
- return new FileInstallArgs(codePath, instructionSets);
- }
-
- static abstract class InstallArgs {
- /** @see InstallParams#origin */
- final OriginInfo origin;
- /** @see InstallParams#move */
- final MoveInfo move;
-
- final IPackageInstallObserver2 observer;
- // Always refers to PackageManager flags only
- final int installFlags;
- @NonNull final InstallSource installSource;
- final String volumeUuid;
- final UserHandle user;
- final String abiOverride;
- final String[] installGrantPermissions;
- final List<String> whitelistedRestrictedPermissions;
- final int autoRevokePermissionsMode;
- /** If non-null, drop an async trace when the install completes */
- final String traceMethod;
- final int traceCookie;
- final SigningDetails signingDetails;
- final int installReason;
- final int mInstallScenario;
- final boolean forceQueryableOverride;
- final int mDataLoaderType;
-
- // The list of instruction sets supported by this app. This is currently
- // only used during the rmdex() phase to clean up resources. We can get rid of this
- // if we move dex files under the common app path.
- /* nullable */ String[] instructionSets;
-
- InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
- int installFlags, InstallSource installSource, String volumeUuid,
- UserHandle user, String[] instructionSets,
- String abiOverride, String[] installGrantPermissions,
- List<String> whitelistedRestrictedPermissions,
- int autoRevokePermissionsMode,
- String traceMethod, int traceCookie, SigningDetails signingDetails,
- int installReason, int installScenario, boolean forceQueryableOverride,
- int dataLoaderType) {
- this.origin = origin;
- this.move = move;
- this.installFlags = installFlags;
- this.observer = observer;
- this.installSource = Preconditions.checkNotNull(installSource);
- this.volumeUuid = volumeUuid;
- this.user = user;
- this.instructionSets = instructionSets;
- this.abiOverride = abiOverride;
- this.installGrantPermissions = installGrantPermissions;
- this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
- this.autoRevokePermissionsMode = autoRevokePermissionsMode;
- this.traceMethod = traceMethod;
- this.traceCookie = traceCookie;
- this.signingDetails = signingDetails;
- this.installReason = installReason;
- this.mInstallScenario = installScenario;
- this.forceQueryableOverride = forceQueryableOverride;
- this.mDataLoaderType = dataLoaderType;
- }
-
- /** New install */
- InstallArgs(InstallParams params) {
- this(params.origin, params.move, params.observer, params.installFlags,
- params.installSource, params.volumeUuid,
- params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
- params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
- params.autoRevokePermissionsMode,
- params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason, params.mInstallScenario, params.forceQueryableOverride,
- params.mDataLoaderType);
- }
-
- abstract int copyApk();
- abstract int doPreInstall(int status);
-
- /**
- * Rename package into final resting place. All paths on the given
- * scanned package should be updated to reflect the rename.
- */
- abstract boolean doRename(int status, ParsedPackage parsedPackage);
- abstract int doPostInstall(int status, int uid);
-
- /** @see PackageSettingBase#getPath() */
- abstract String getCodePath();
-
- // Need installer lock especially for dex file removal.
- abstract void cleanUpResourcesLI();
- abstract boolean doPostDeleteLI(boolean delete);
-
- /**
- * Called before the source arguments are copied. This is used mostly
- * for MoveParams when it needs to read the source file to put it in the
- * destination.
- */
- int doPreCopy() {
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- /**
- * Called after the source arguments are copied. This is used mostly for
- * MoveParams when it needs to read the source file to put it in the
- * destination.
- */
- int doPostCopy(int uid) {
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- protected boolean isEphemeral() {
- return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- }
-
- UserHandle getUser() {
- return user;
- }
- }
-
- void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
- if (!allCodePaths.isEmpty()) {
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String codePath : allCodePaths) {
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- try {
- mInstaller.rmdex(codePath, dexCodeInstructionSet);
- } catch (InstallerException ignored) {
- }
- }
- }
- }
- }
-
- /**
- * Logic to handle installation of new applications, including copying
- * and renaming logic.
- */
- class FileInstallArgs extends InstallArgs {
- private File codeFile;
- private File resourceFile;
-
- // Example topology:
- // /data/app/com.example/base.apk
- // /data/app/com.example/split_foo.apk
- // /data/app/com.example/lib/arm/libfoo.so
- // /data/app/com.example/lib/arm64/libfoo.so
- // /data/app/com.example/dalvik/arm/base.apk@classes.dex
-
- /** New install */
- FileInstallArgs(InstallParams params) {
- super(params);
- }
-
- /** Existing install */
- FileInstallArgs(String codePath, String[] instructionSets) {
- super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
- null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
- SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
- false, DataLoaderType.NONE);
- this.codeFile = (codePath != null) ? new File(codePath) : null;
- }
-
- int copyApk() {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
- try {
- return doCopyApk();
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- private int doCopyApk() {
- if (origin.staged) {
- if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
- codeFile = origin.file;
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- try {
- final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- final File tempDir =
- mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
- codeFile = tempDir;
- } catch (IOException e) {
- Slog.w(TAG, "Failed to create copy file: " + e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
-
- int ret = PackageManagerServiceUtils.copyPackage(
- origin.file.getAbsolutePath(), codeFile);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to copy package");
- return ret;
- }
-
- final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
- final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(codeFile);
- ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- abiOverride, isIncremental);
- } catch (IOException e) {
- Slog.e(TAG, "Copying native libraries failed", e);
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- } finally {
- IoUtils.closeQuietly(handle);
- }
-
- return ret;
- }
-
- int doPreInstall(int status) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp();
- }
- return status;
- }
-
- @Override
- boolean doRename(int status, ParsedPackage parsedPackage) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp();
- return false;
- }
-
- final File targetDir = resolveTargetDir();
- final File beforeCodeFile = codeFile;
- final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
-
- if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
- final boolean onIncremental = mIncrementalManager != null
- && isIncrementalPath(beforeCodeFile.getAbsolutePath());
- try {
- makeDirRecursive(afterCodeFile.getParentFile(), 0775);
- if (onIncremental) {
- // Just link files here. The stage dir will be removed when the installation
- // session is completed.
- mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
- } else {
- Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
- }
- } catch (IOException | ErrnoException e) {
- Slog.w(TAG, "Failed to rename", e);
- return false;
- }
-
- if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
- Slog.w(TAG, "Failed to restorecon");
- return false;
- }
-
- // Reflect the rename internally
- codeFile = afterCodeFile;
-
- // Reflect the rename in scanned details
- try {
- parsedPackage.setCodePath(afterCodeFile.getCanonicalPath());
- } catch (IOException e) {
- Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
- return false;
- }
- parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, parsedPackage.getBaseApkPath()));
- parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, parsedPackage.getSplitCodePaths()));
-
- return true;
- }
-
- // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
- // flow, we won't need this method anymore.
- private File resolveTargetDir() {
- boolean isStagedInstall = (installFlags & INSTALL_STAGED) != 0;
- if (isStagedInstall) {
- return Environment.getDataAppDirectory(null);
- } else {
- return codeFile.getParentFile();
- }
- }
-
- int doPostInstall(int status, int uid) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp();
- }
- return status;
- }
-
- @Override
- String getCodePath() {
- return (codeFile != null) ? codeFile.getAbsolutePath() : null;
- }
-
- private boolean cleanUp() {
- if (codeFile == null || !codeFile.exists()) {
- return false;
- }
- removeCodePathLI(codeFile);
- return true;
- }
-
- void cleanUpResourcesLI() {
- // Try enumerating all code paths before deleting
- List<String> allCodePaths = Collections.EMPTY_LIST;
- if (codeFile != null && codeFile.exists()) {
- final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
- final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
- input.reset(), codeFile, /* flags */ 0);
- if (result.isSuccess()) {
- // Ignore error; we tried our best
- allCodePaths = result.getResult().getAllApkPaths();
- }
- }
-
- cleanUp();
- removeDexFiles(allCodePaths, instructionSets);
- }
-
- boolean doPostDeleteLI(boolean delete) {
- // XXX err, shouldn't we respect the delete flag?
- cleanUpResourcesLI();
- return true;
- }
- }
-
- /**
- * Logic to handle movement of existing installed applications.
- */
- class MoveInstallArgs extends InstallArgs {
- private File codeFile;
-
- /** New install */
- MoveInstallArgs(InstallParams params) {
- super(params);
- }
-
- int copyApk() {
- if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
- + move.fromUuid + " to " + move.toUuid);
- synchronized (mInstaller) {
- try {
- mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
- move.appId, move.seinfo, move.targetSdkVersion,
- move.fromCodePath);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to move app", e);
- return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- }
- }
-
- final String toPathName = new File(move.fromCodePath).getName();
- codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
- if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- int doPreInstall(int status) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp(move.toUuid);
- }
- return status;
- }
-
- @Override
- boolean doRename(int status, ParsedPackage parsedPackage) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp(move.toUuid);
- return false;
- }
-
- return true;
- }
-
- int doPostInstall(int status, int uid) {
- if (status == PackageManager.INSTALL_SUCCEEDED) {
- cleanUp(move.fromUuid);
- } else {
- cleanUp(move.toUuid);
- }
- return status;
- }
-
- @Override
- String getCodePath() {
- return (codeFile != null) ? codeFile.getAbsolutePath() : null;
- }
-
- private boolean cleanUp(String volumeUuid) {
- final String toPathName = new File(move.fromCodePath).getName();
- final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
- toPathName);
- Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
- final int[] userIds = mUserManager.getUserIds();
- synchronized (mInstallLock) {
- // Clean up both app data and code
- // All package moves are frozen until finished
-
- // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
- // this task was only focused on moving data on internal storage.
- // We don't want ART profiles cleared, because they don't move,
- // so we would be deleting the only copy (b/149200535).
- final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
- for (int userId : userIds) {
- try {
- mInstaller.destroyAppData(volumeUuid, move.packageName, userId, flags, 0);
- } catch (InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
- }
- }
- removeCodePathLI(codeFile);
- }
- return true;
- }
-
- void cleanUpResourcesLI() {
- throw new UnsupportedOperationException();
- }
-
- boolean doPostDeleteLI(boolean delete) {
- throw new UnsupportedOperationException();
- }
+ InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
+ return new FileInstallArgs(codePath, instructionSets, this);
}
/**
@@ -19002,7 +16965,7 @@
* directory.
* @return File object for the directory that should hold the code files of {@code packageName}.
*/
- private File getNextCodePath(File targetDir, String packageName) {
+ static File getNextCodePath(File targetDir, String packageName) {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[16];
File firstLevelDir;
@@ -19017,60 +16980,6 @@
return new File(firstLevelDir, packageName + "-" + suffix);
}
- static class PackageInstalledInfo {
- String name;
- int uid;
- // The set of users that originally had this package installed.
- int[] origUsers;
- // The set of users that now have this package installed.
- int[] newUsers;
- AndroidPackage pkg;
- int returnCode;
- String returnMsg;
- String installerPackageName;
- PackageRemovedInfo removedInfo;
- // The set of packages consuming this shared library or null if no consumers exist.
- ArrayList<AndroidPackage> libraryConsumers;
- PackageFreezer freezer;
-
- public void setError(int code, String msg) {
- setReturnCode(code);
- setReturnMessage(msg);
- 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));
- Slog.w(TAG, msg, e);
- }
-
- public void setReturnCode(int returnCode) {
- this.returnCode = returnCode;
- }
-
- private void setReturnMessage(String returnMsg) {
- this.returnMsg = returnMsg;
- }
-
- // In some error cases we want to convey more info back to the observer
- String origPackage;
- String origPermission;
- }
-
- private static void updateDigest(MessageDigest digest, File file) throws IOException {
- try (DigestInputStream digestStream =
- new DigestInputStream(new FileInputStream(file), digest)) {
- while (digestStream.read() != -1) {} // nothing to do; just plow through the file
- }
- }
-
private void removeNativeBinariesLI(PackageSetting ps) {
if (ps != null) {
NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
@@ -19083,361 +16992,18 @@
}
@GuardedBy("mLock")
- private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
- return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
- }
-
- private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
- int[] allUsers, PackageInstalledInfo res) {
- updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
- }
-
- private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
- int[] allUsers, PackageInstalledInfo res) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
-
- final String pkgName = pkg.getPackageName();
- final int[] installedForUsers = res.origUsers;
- final int installReason = installArgs.installReason;
- InstallSource installSource = installArgs.installSource;
- final String installerPackageName = installSource.installerPackageName;
-
- if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
- synchronized (mLock) {
- // For system-bundled packages, we assume that installing an upgraded version
- // of the package implies that the user actually wants to run that new code,
- // so we enable the package.
- final PackageSetting ps = mSettings.getPackageLPr(pkgName);
- final int userId = installArgs.user.getIdentifier();
- if (ps != null) {
- if (pkg.isSystem()) {
- if (DEBUG_INSTALL) {
- Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
- }
- // Enable system package for requested users
- if (res.origUsers != null) {
- for (int origUserId : res.origUsers) {
- if (userId == UserHandle.USER_ALL || userId == origUserId) {
- ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
- origUserId, installerPackageName);
- }
- }
- }
- // Also convey the prior install/uninstall state
- if (allUsers != null && installedForUsers != null) {
- for (int currentUserId : allUsers) {
- final boolean installed = ArrayUtils.contains(
- installedForUsers, currentUserId);
- if (DEBUG_INSTALL) {
- Slog.d(TAG, " user " + currentUserId + " => " + installed);
- }
- ps.setInstalled(installed, currentUserId);
- }
- // these install state changes will be persisted in the
- // upcoming call to mSettings.writeLPr().
- }
-
- if (allUsers != null) {
- for (int currentUserId : allUsers) {
- ps.resetOverrideComponentLabelIcon(currentUserId);
- }
- }
- }
-
- // Retrieve the overlays for shared libraries of the package.
- if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
- for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
- for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
- if (!sharedLib.isDynamic()) {
- // TODO(146804378): Support overlaying static shared libraries
- continue;
- }
- final PackageSetting libPs = mSettings.getPackageLPr(
- sharedLib.getPackageName());
- if (libPs == null) {
- continue;
- }
- ps.setOverlayPathsForLibrary(sharedLib.getName(),
- libPs.getOverlayPaths(currentUserId), currentUserId);
- }
- }
- }
-
- // It's implied that when a user requests installation, they want the app to be
- // installed and enabled. (This does not apply to USER_ALL, which here means only
- // install on users for which the app is already installed).
- if (userId != UserHandle.USER_ALL) {
- ps.setInstalled(true, userId);
- ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
- }
-
- mSettings.addInstallerPackageNames(ps.installSource);
-
- // When replacing an existing package, preserve the original install reason for all
- // users that had the package installed before. Similarly for uninstall reasons.
- final Set<Integer> previousUserIds = new ArraySet<>();
- if (res.removedInfo != null && res.removedInfo.installReasons != null) {
- final int installReasonCount = res.removedInfo.installReasons.size();
- for (int i = 0; i < installReasonCount; i++) {
- final int previousUserId = res.removedInfo.installReasons.keyAt(i);
- final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);
- ps.setInstallReason(previousInstallReason, previousUserId);
- previousUserIds.add(previousUserId);
- }
- }
- if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) {
- for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) {
- final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i);
- final int previousReason = res.removedInfo.uninstallReasons.valueAt(i);
- ps.setUninstallReason(previousReason, previousUserId);
- }
- }
-
- // Set install reason for users that are having the package newly installed.
- final int[] allUsersList = mUserManager.getUserIds();
- if (userId == UserHandle.USER_ALL) {
- // TODO(b/152629990): It appears that the package doesn't actually get newly
- // installed in this case, so the installReason shouldn't get modified?
- for (int currentUserId : allUsersList) {
- if (!previousUserIds.contains(currentUserId)) {
- ps.setInstallReason(installReason, currentUserId);
- }
- }
- } else if (!previousUserIds.contains(userId)) {
- ps.setInstallReason(installReason, userId);
- }
-
- // TODO(b/169721400): generalize Incremental States and create a Callback object
- // that can be used for all the packages.
- final String codePath = ps.getPathString();
- if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) {
- final IncrementalStatesCallback incrementalStatesCallback =
- new IncrementalStatesCallback(ps.name,
- UserHandle.getUid(userId, ps.appId),
- getInstalledUsers(ps, userId));
- ps.setIncrementalStatesCallback(incrementalStatesCallback);
- mIncrementalManager.registerLoadingProgressCallback(codePath,
- new IncrementalProgressListener(ps.name));
- }
-
- // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
- for (int currentUserId : allUsersList) {
- if (ps.getInstalled(currentUserId)) {
- ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
- }
- }
-
- mSettings.writeKernelMappingLPr(ps);
-
- final PermissionManagerServiceInternal.PackageInstalledParams.Builder
- permissionParamsBuilder =
- new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
- final boolean grantPermissions = (installArgs.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
- if (grantPermissions) {
- final List<String> grantedPermissions =
- installArgs.installGrantPermissions != null
- ? Arrays.asList(installArgs.installGrantPermissions)
- : pkg.getRequestedPermissions();
- permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
- }
- final boolean allowlistAllRestrictedPermissions =
- (installArgs.installFlags
- & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
- final List<String> allowlistedRestrictedPermissions =
- allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
- : installArgs.whitelistedRestrictedPermissions;
- if (allowlistedRestrictedPermissions != null) {
- permissionParamsBuilder.setAllowlistedRestrictedPermissions(
- allowlistedRestrictedPermissions);
- }
- final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;
- permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
- mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId);
- }
- res.name = pkgName;
- res.uid = pkg.getUid();
- res.pkg = pkg;
- res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- //to update install status
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- writeSettingsLPrTEMP();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- private static class InstallRequest {
- public final InstallArgs args;
- public final PackageInstalledInfo installResult;
-
- private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
- this.args = args;
- this.installResult = res;
- }
- }
-
- @GuardedBy("mInstallLock")
- private void installPackagesTracedLI(List<InstallRequest> requests) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
- installPackagesLI(requests);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- /**
- * Package state to commit to memory and disk after reconciliation has completed.
- */
- private static class CommitRequest {
- final Map<String, ReconciledPackage> reconciledPackages;
- @NonNull
- final int[] mAllUsers;
-
- private CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
- @NonNull int[] allUsers) {
- this.reconciledPackages = reconciledPackages;
- this.mAllUsers = allUsers;
- }
- }
-
- /**
- * Package scan results and related request details used to reconcile the potential addition of
- * one or more packages to the system.
- *
- * Reconcile will take a set of package details that need to be committed to the system and make
- * sure that they are valid in the context of the system and the other installing apps. Any
- * invalid state or app will result in a failed reconciliation and thus whatever operation (such
- * as install) led to the request.
- */
- private static class ReconcileRequest {
- public final Map<String, ScanResult> scannedPackages;
-
- public final Map<String, AndroidPackage> allPackages;
- public final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
- public final Map<String, InstallArgs> installArgs;
- public final Map<String, PackageInstalledInfo> installResults;
- public final Map<String, PrepareResult> preparedPackages;
- public final Map<String, VersionInfo> versionInfos;
- public final Map<String, PackageSetting> lastStaticSharedLibSettings;
-
- private ReconcileRequest(Map<String, ScanResult> scannedPackages,
- Map<String, InstallArgs> installArgs,
- Map<String, PackageInstalledInfo> installResults,
- Map<String, PrepareResult> preparedPackages,
- Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
- Map<String, AndroidPackage> allPackages,
- Map<String, VersionInfo> versionInfos,
- Map<String, PackageSetting> lastStaticSharedLibSettings) {
- this.scannedPackages = scannedPackages;
- this.installArgs = installArgs;
- this.installResults = installResults;
- this.preparedPackages = preparedPackages;
- this.sharedLibrarySource = sharedLibrarySource;
- this.allPackages = allPackages;
- this.versionInfos = versionInfos;
- this.lastStaticSharedLibSettings = lastStaticSharedLibSettings;
- }
-
- private ReconcileRequest(Map<String, ScanResult> scannedPackages,
- Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
- Map<String, AndroidPackage> allPackages,
- Map<String, VersionInfo> versionInfos,
- Map<String, PackageSetting> lastStaticSharedLibSettings) {
- this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
- Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
- lastStaticSharedLibSettings);
- }
- }
- private static class ReconcileFailure extends PackageManagerException {
- ReconcileFailure(String message) {
- super("Reconcile failed: " + message);
- }
- ReconcileFailure(int reason, String message) {
- super(reason, "Reconcile failed: " + message);
- }
- ReconcileFailure(PackageManagerException e) {
- this(e.error, e.getMessage());
- }
- }
-
- /**
- * A container of all data needed to commit a package to in-memory data structures and to disk.
- * TODO: move most of the data contained here into a PackageSetting for commit.
- */
- private static class ReconciledPackage {
- public final ReconcileRequest request;
- public final PackageSetting pkgSetting;
- public final ScanResult scanResult;
- // TODO: Remove install-specific details from the reconcile result
- public final PackageInstalledInfo installResult;
- @Nullable public final PrepareResult prepareResult;
- @Nullable public final InstallArgs installArgs;
- public final DeletePackageAction deletePackageAction;
- public final List<SharedLibraryInfo> allowedSharedLibraryInfos;
- public final SigningDetails signingDetails;
- public final boolean sharedUserSignaturesChanged;
- public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
- public final boolean removeAppKeySetData;
-
- private ReconciledPackage(ReconcileRequest request,
- InstallArgs installArgs,
- PackageSetting pkgSetting,
- PackageInstalledInfo installResult,
- PrepareResult prepareResult,
- ScanResult scanResult,
- DeletePackageAction deletePackageAction,
- List<SharedLibraryInfo> allowedSharedLibraryInfos,
- SigningDetails signingDetails,
- boolean sharedUserSignaturesChanged,
- boolean removeAppKeySetData) {
- this.request = request;
- this.installArgs = installArgs;
- this.pkgSetting = pkgSetting;
- this.installResult = installResult;
- this.prepareResult = prepareResult;
- this.scanResult = scanResult;
- this.deletePackageAction = deletePackageAction;
- this.allowedSharedLibraryInfos = allowedSharedLibraryInfos;
- this.signingDetails = signingDetails;
- this.sharedUserSignaturesChanged = sharedUserSignaturesChanged;
- this.removeAppKeySetData = removeAppKeySetData;
- }
-
- /**
- * Returns a combined set of packages containing the packages already installed combined
- * with the package(s) currently being installed. The to-be installed packages take
- * precedence and may shadow already installed packages.
- */
- private Map<String, AndroidPackage> getCombinedAvailablePackages() {
- final ArrayMap<String, AndroidPackage> combined =
- new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
-
- combined.putAll(request.allPackages);
-
- for (ScanResult scanResult : request.scannedPackages.values()) {
- combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
- }
-
- return combined;
- }
- }
-
- @GuardedBy("mLock")
- private static Map<String, ReconciledPackage> reconcilePackagesLocked(
+ static Map<String, ReconciledPackage> reconcilePackagesLocked(
final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
throws ReconcileFailure {
- final Map<String, ScanResult> scannedPackages = request.scannedPackages;
+ final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
// make a copy of the existing set of packages so we can combine them with incoming packages
final ArrayMap<String, AndroidPackage> combinedPackages =
- new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+ new ArrayMap<>(request.mAllPackages.size() + scannedPackages.size());
- combinedPackages.putAll(request.allPackages);
+ combinedPackages.putAll(request.mAllPackages);
final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
new ArrayMap<>();
@@ -19446,12 +17012,12 @@
final ScanResult scanResult = scannedPackages.get(installPackageName);
// add / replace existing with incoming packages
- combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
+ combinedPackages.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage);
// in the first pass, we'll build up the set of incoming shared libraries
final List<SharedLibraryInfo> allowedSharedLibInfos =
- getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource);
- final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo;
+ getAllowedSharedLibInfos(scanResult, request.mSharedLibrarySource);
+ final SharedLibraryInfo staticLib = scanResult.mStaticSharedLibraryInfo;
if (allowedSharedLibInfos != null) {
for (SharedLibraryInfo info : allowedSharedLibInfos) {
if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) {
@@ -19462,9 +17028,9 @@
}
// the following may be null if we're just reconciling on boot (and not during install)
- final InstallArgs installArgs = request.installArgs.get(installPackageName);
- final PackageInstalledInfo res = request.installResults.get(installPackageName);
- final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
+ final InstallArgs installArgs = request.mInstallArgs.get(installPackageName);
+ final PackageInstalledInfo res = request.mInstallResults.get(installPackageName);
+ final PrepareResult prepareResult = request.mPreparedPackages.get(installPackageName);
final boolean isInstall = installArgs != null;
if (isInstall && (res == null || prepareResult == null)) {
throw new ReconcileFailure("Reconcile arguments are not balanced for "
@@ -19473,12 +17039,12 @@
final DeletePackageAction deletePackageAction;
// we only want to try to delete for non system apps
- if (isInstall && prepareResult.replace && !prepareResult.system) {
- final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0;
+ if (isInstall && prepareResult.mReplace && !prepareResult.mSystem) {
+ final boolean killApp = (scanResult.mRequest.mScanFlags & SCAN_DONT_KILL_APP) == 0;
final int deleteFlags = PackageManager.DELETE_KEEP_DATA
| (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
- deletePackageAction = mayDeletePackageLocked(res.removedInfo,
- prepareResult.originalPs, prepareResult.disabledPs,
+ deletePackageAction = mayDeletePackageLocked(res.mRemovedInfo,
+ prepareResult.mOriginalPs, prepareResult.mDisabledPs,
deleteFlags, null /* all users */);
if (deletePackageAction == null) {
throw new ReconcileFailure(
@@ -19489,17 +17055,17 @@
deletePackageAction = null;
}
- final int scanFlags = scanResult.request.scanFlags;
- final int parseFlags = scanResult.request.parseFlags;
- final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
+ final int scanFlags = scanResult.mRequest.mScanFlags;
+ final int parseFlags = scanResult.mRequest.mParseFlags;
+ final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
- final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
+ final PackageSetting disabledPkgSetting = scanResult.mRequest.mDisabledPkgSetting;
final PackageSetting lastStaticSharedLibSetting =
- request.lastStaticSharedLibSettings.get(installPackageName);
+ request.mLastStaticSharedLibSettings.get(installPackageName);
final PackageSetting signatureCheckPs =
(prepareResult != null && lastStaticSharedLibSetting != null)
? lastStaticSharedLibSetting
- : scanResult.pkgSetting;
+ : scanResult.mPkgSetting;
boolean removeAppKeySetData = false;
boolean sharedUserSignaturesChanged = false;
SigningDetails signingDetails = null;
@@ -19522,11 +17088,11 @@
signingDetails = parsedPackage.getSigningDetails();
} else {
try {
- final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
+ final VersionInfo versionInfo = request.mVersionInfos.get(installPackageName);
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
final boolean isRollback = installArgs != null
- && installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+ && installArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
final boolean compatMatch = verifySignatures(signatureCheckPs,
disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
compareRecover, isRollback);
@@ -19590,7 +17156,7 @@
throw new ReconcileFailure(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Signature mismatch for shared user: "
- + scanResult.pkgSetting.sharedUser);
+ + scanResult.mPkgSetting.sharedUser);
} else {
// Treat mismatched signatures on system packages using a shared
// UID as
@@ -19600,7 +17166,7 @@
"Signature mismatch on system package "
+ parsedPackage.getPackageName()
+ " for shared user "
- + scanResult.pkgSetting.sharedUser);
+ + scanResult.mPkgSetting.sharedUser);
}
}
@@ -19623,8 +17189,8 @@
}
result.put(installPackageName,
- new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
- res, request.preparedPackages.get(installPackageName), scanResult,
+ new ReconciledPackage(request, installArgs, scanResult.mPkgSetting,
+ res, request.mPreparedPackages.get(installPackageName), scanResult,
deletePackageAction, allowedSharedLibInfos, signingDetails,
sharedUserSignaturesChanged, removeAppKeySetData));
}
@@ -19638,15 +17204,15 @@
// scan don't update any libs as we do this wholesale after all
// apps are scanned to avoid dependency based scanning.
final ScanResult scanResult = scannedPackages.get(installPackageName);
- if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0
- || (scanResult.request.parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
+ if ((scanResult.mRequest.mScanFlags & SCAN_BOOTING) != 0
+ || (scanResult.mRequest.mParseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
!= 0) {
continue;
}
try {
- result.get(installPackageName).collectedSharedLibraryInfos =
- collectSharedLibraryInfos(scanResult.request.parsedPackage,
- combinedPackages, request.sharedLibrarySource,
+ result.get(installPackageName).mCollectedSharedLibraryInfos =
+ collectSharedLibraryInfos(scanResult.mRequest.mParsedPackage,
+ combinedPackages, request.mSharedLibrarySource,
incomingSharedLibraries, injector.getCompatibility());
} catch (PackageManagerException e) {
@@ -19665,29 +17231,29 @@
ScanResult scanResult,
Map<String, WatchedLongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
// Let's used the parsed package as scanResult.pkgSetting may be null
- final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
- if (scanResult.staticSharedLibraryInfo == null
- && scanResult.dynamicSharedLibraryInfos == null) {
+ final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
+ if (scanResult.mStaticSharedLibraryInfo == null
+ && scanResult.mDynamicSharedLibraryInfos == null) {
return null;
}
// Any app can add new static shared libraries
- if (scanResult.staticSharedLibraryInfo != null) {
- return Collections.singletonList(scanResult.staticSharedLibraryInfo);
+ if (scanResult.mStaticSharedLibraryInfo != null) {
+ return Collections.singletonList(scanResult.mStaticSharedLibraryInfo);
}
final boolean hasDynamicLibraries = parsedPackage.isSystem()
- && scanResult.dynamicSharedLibraryInfos != null;
+ && scanResult.mDynamicSharedLibraryInfos != null;
if (!hasDynamicLibraries) {
return null;
}
- final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState()
+ final boolean isUpdatedSystemApp = scanResult.mPkgSetting.getPkgState()
.isUpdatedSystemApp();
// We may not yet have disabled the updated package yet, so be sure to grab the
// current setting if that's the case.
final PackageSetting updatedSystemPs = isUpdatedSystemApp
- ? scanResult.request.disabledPkgSetting == null
- ? scanResult.request.oldPkgSetting
- : scanResult.request.disabledPkgSetting
+ ? scanResult.mRequest.mDisabledPkgSetting == null
+ ? scanResult.mRequest.mOldPkgSetting
+ : scanResult.mRequest.mDisabledPkgSetting
: null;
if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
|| updatedSystemPs.pkg.getLibraryNames() == null)) {
@@ -19696,8 +17262,8 @@
return null;
}
final ArrayList<SharedLibraryInfo> infos =
- new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size());
- for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) {
+ new ArrayList<>(scanResult.mDynamicSharedLibraryInfos.size());
+ for (SharedLibraryInfo info : scanResult.mDynamicSharedLibraryInfos) {
final String name = info.getName();
if (isUpdatedSystemApp) {
// New library entries can only be added through the
@@ -19751,509 +17317,6 @@
return true;
}
- @GuardedBy("mLock")
- private void commitPackagesLocked(final CommitRequest request) {
- // TODO: remove any expected failures from this method; this should only be able to fail due
- // to unavoidable errors (I/O, etc.)
- for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
- final ScanResult scanResult = reconciledPkg.scanResult;
- final ScanRequest scanRequest = scanResult.request;
- final ParsedPackage parsedPackage = scanRequest.parsedPackage;
- final String packageName = parsedPackage.getPackageName();
- final PackageInstalledInfo res = reconciledPkg.installResult;
-
- if (reconciledPkg.prepareResult.replace) {
- AndroidPackage oldPackage = mPackages.get(packageName);
-
- // Set the update and install times
- PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());
- reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
- reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
-
- res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
- reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked());
- if (reconciledPkg.prepareResult.system) {
- // Remove existing system package
- removePackageLI(oldPackage, true);
- if (!disableSystemPackageLPw(oldPackage)) {
- // We didn't need to disable the .apk as a current system package,
- // which means we are replacing another update that is already
- // installed. We need to make sure to delete the older one's .apk.
- res.removedInfo.args = createInstallArgsForExisting(
- oldPackage.getPath(),
- getAppDexInstructionSets(
- AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
- deletedPkgSetting),
- AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
- deletedPkgSetting)));
- } else {
- res.removedInfo.args = null;
- }
- } else {
- try {
- // Settings will be written during the call to updateSettingsLI().
- executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
- true, request.mAllUsers, false, parsedPackage);
- } catch (SystemDeleteException e) {
- if (mIsEngBuild) {
- throw new RuntimeException("Unexpected failure", e);
- // ignore; not possible for non-system app
- }
- }
- // Successfully deleted the old package; proceed with replace.
-
- // If deleted package lived in a container, give users a chance to
- // relinquish resources before killing.
- if (oldPackage.isExternalStorage()) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + oldPackage
- + " is ASEC-hosted -> UNAVAILABLE");
- }
- final int[] uidArray = new int[]{oldPackage.getUid()};
- final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(oldPackage.getPackageName());
- sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
- }
-
- // Update the in-memory copy of the previous code paths.
- PackageSetting ps1 = mSettings.getPackageLPr(
- reconciledPkg.prepareResult.existingPackage.getPackageName());
- if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
- == 0) {
- if (ps1.mOldCodePaths == null) {
- ps1.mOldCodePaths = new ArraySet<>();
- }
- Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());
- if (oldPackage.getSplitCodePaths() != null) {
- Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
- }
- } else {
- ps1.mOldCodePaths = null;
- }
-
- if (reconciledPkg.installResult.returnCode
- == PackageManager.INSTALL_SUCCEEDED) {
- PackageSetting ps2 = mSettings.getPackageLPr(
- parsedPackage.getPackageName());
- if (ps2 != null) {
- res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
- }
- }
- }
- }
-
- AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
- updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
-
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null) {
- res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
- ps.setUpdateAvailable(false /*updateAvailable*/);
- }
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- updateSequenceNumberLP(ps, res.newUsers);
- updateInstantAppInstallerLocked(packageName);
- }
- }
- ApplicationPackageManager.invalidateGetPackagesForUidCache();
- }
-
- /**
- * Installs one or more packages atomically. This operation is broken up into four phases:
- * <ul>
- * <li><b>Prepare</b>
- * <br/>Analyzes any current install state, parses the package and does initial
- * validation on it.</li>
- * <li><b>Scan</b>
- * <br/>Interrogates the parsed packages given the context collected in prepare.</li>
- * <li><b>Reconcile</b>
- * <br/>Validates scanned packages in the context of each other and the current system
- * state to ensure that the install will be successful.
- * <li><b>Commit</b>
- * <br/>Commits all scanned packages and updates system state. This is the only place
- * that system state may be modified in the install flow and all predictable errors
- * must be determined before this phase.</li>
- * </ul>
- *
- * Failure at any phase will result in a full failure to install all packages.
- */
- @GuardedBy("mInstallLock")
- private void installPackagesLI(List<InstallRequest> requests) {
- final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
- final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
- final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
- final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
- final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
- final Map<String, PackageSetting> lastStaticSharedLibSettings =
- new ArrayMap<>(requests.size());
- final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
- boolean success = false;
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
- for (InstallRequest request : requests) {
- // TODO(b/109941548): remove this once we've pulled everything from it and into
- // scan, reconcile or commit.
- final PrepareResult prepareResult;
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
- prepareResult =
- preparePackageLI(request.args, request.installResult);
- } catch (PrepareFailure prepareFailure) {
- request.installResult.setError(prepareFailure.error,
- prepareFailure.getMessage());
- request.installResult.origPackage = prepareFailure.conflictingPackage;
- request.installResult.origPermission = prepareFailure.conflictingPermission;
- return;
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- request.installResult.installerPackageName =
- request.args.installSource.installerPackageName;
-
- final String packageName = prepareResult.packageToScan.getPackageName();
- prepareResults.put(packageName, prepareResult);
- installResults.put(packageName, request.installResult);
- installArgs.put(packageName, request.args);
- try {
- final ScanResult result = scanPackageTracedLI(
- prepareResult.packageToScan, prepareResult.parseFlags,
- prepareResult.scanFlags, System.currentTimeMillis(),
- request.args.user, request.args.abiOverride);
- if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
- request.installResult.setError(
- PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Duplicate package " + result.pkgSetting.pkg.getPackageName()
- + " in multi-package install request.");
- return;
- }
- createdAppId.put(packageName, optimisticallyRegisterAppId(result));
- versionInfos.put(result.pkgSetting.pkg.getPackageName(),
- getSettingsVersionForPackage(result.pkgSetting.pkg));
- if (result.staticSharedLibraryInfo != null) {
- final PackageSetting sharedLibLatestVersionSetting =
- getSharedLibLatestVersionSetting(result);
- if (sharedLibLatestVersionSetting != null) {
- lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
- sharedLibLatestVersionSetting);
- }
- }
- } catch (PackageManagerException e) {
- request.installResult.setError("Scanning Failed.", e);
- return;
- }
- }
- ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
- installResults,
- prepareResults,
- mSharedLibraries,
- Collections.unmodifiableMap(mPackages), versionInfos,
- lastStaticSharedLibSettings);
- CommitRequest commitRequest = null;
- synchronized (mLock) {
- Map<String, ReconciledPackage> reconciledPackages;
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
- reconciledPackages = reconcilePackagesLocked(
- reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
- } catch (ReconcileFailure e) {
- for (InstallRequest request : requests) {
- request.installResult.setError("Reconciliation failed...", e);
- }
- return;
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
- commitRequest = new CommitRequest(reconciledPackages,
- mUserManager.getUserIds());
- commitPackagesLocked(commitRequest);
- success = true;
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
- executePostCommitSteps(commitRequest);
- } finally {
- if (success) {
- for (InstallRequest request : requests) {
- final InstallArgs args = request.args;
- if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
- continue;
- }
- if (args.signingDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
- continue;
- }
- // For incremental installs, we bypass the verifier prior to install. Now
- // that we know the package is valid, send a notice to the verifier with
- // the root hash of the base.apk.
- final String baseCodePath = request.installResult.pkg.getBaseApkPath();
- final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
- final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
- final int verificationId = mPendingVerificationToken++;
- final String rootHashString = PackageManagerServiceUtils
- .buildVerificationRootHashString(baseCodePath, splitCodePaths);
- broadcastPackageVerified(verificationId, originUri,
- PackageManager.VERIFICATION_ALLOW, rootHashString,
- args.mDataLoaderType, args.getUser());
- }
- } else {
- for (ScanResult result : preparedScans.values()) {
- if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
- false)) {
- cleanUpAppIdCreation(result);
- }
- }
- // TODO(patb): create a more descriptive reason than unknown in future release
- // mark all non-failure installs as UNKNOWN so we do not treat them as success
- for (InstallRequest request : requests) {
- if (request.installResult.freezer != null) {
- request.installResult.freezer.close();
- }
- if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
- }
- }
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- /**
- * On successful install, executes remaining steps after commit completes and the package lock
- * is released. These are typically more expensive or require calls to installd, which often
- * locks on {@link #mLock}.
- */
- private void executePostCommitSteps(CommitRequest commitRequest) {
- final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
- for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
- final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
- & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
- final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
- final String packageName = pkg.getPackageName();
- final String codePath = pkg.getPath();
- final boolean onIncremental = mIncrementalManager != null
- && isIncrementalPath(codePath);
- if (onIncremental) {
- IncrementalStorage storage = mIncrementalManager.openStorage(codePath);
- if (storage == null) {
- throw new IllegalArgumentException(
- "Install: null storage for incremental package " + packageName);
- }
- incrementalStorages.add(storage);
- }
- prepareAppDataAfterInstallLIF(pkg);
- if (reconciledPkg.prepareResult.clearCodeCache) {
- clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- }
- if (reconciledPkg.prepareResult.replace) {
- mDexManager.notifyPackageUpdated(pkg.getPackageName(),
- pkg.getBaseApkPath(), pkg.getSplitCodePaths());
- }
-
- // Prepare the application profiles for the new code paths.
- // This needs to be done before invoking dexopt so that any install-time profile
- // can be used for optimizations.
- mArtManagerService.prepareAppProfiles(
- pkg,
- resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
- /* updateReferenceProfileContent= */ true);
-
- // Compute the compilation reason from the installation scenario.
- final int compilationReason = mDexManager.getCompilationReasonForInstallScenario(
- reconciledPkg.installArgs.mInstallScenario);
-
- // Construct the DexoptOptions early to see if we should skip running dexopt.
- //
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- final boolean isBackupOrRestore =
- reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE
- || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP;
-
- final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
- | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
- | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);
- DexoptOptions dexoptOptions =
- new DexoptOptions(packageName, compilationReason, dexoptFlags);
-
- // Check whether we need to dexopt the app.
- //
- // NOTE: it is IMPORTANT to call dexopt:
- // - after doRename which will sync the package data from AndroidPackage and
- // its corresponding ApplicationInfo.
- // - after installNewPackageLIF or replacePackageLIF which will update result with the
- // uid of the application (pkg.applicationInfo.uid).
- // This update happens in place!
- //
- // We only need to dexopt if the package meets ALL of the following conditions:
- // 1) it is not an instant app or if it is then dexopt is enabled via gservices.
- // 2) it is not debuggable.
- // 3) it is not on Incremental File System.
- //
- // Note that we do not dexopt instant apps by default. dexopt can take some time to
- // complete, so we skip this step during installation. Instead, we'll take extra time
- // the first time the instant app starts. It's preferred to do it this way to provide
- // continuous progress to the useur instead of mysteriously blocking somewhere in the
- // middle of running an instant app. The default behaviour can be overridden
- // via gservices.
- //
- // Furthermore, dexopt may be skipped, depending on the install scenario and current
- // state of the device.
- //
- // TODO(b/174695087): instantApp and onIncremental should be removed and their install
- // path moved to SCENARIO_FAST.
- final boolean performDexopt =
- (!instantApp || Global.getInt(mContext.getContentResolver(),
- Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
- && !pkg.isDebuggable()
- && (!onIncremental)
- && dexoptOptions.isCompilationEnabled();
-
- if (performDexopt) {
- // Compile the layout resources.
- if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
- mViewCompiler.compileLayouts(pkg);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- ScanResult result = reconciledPkg.scanResult;
-
- // This mirrors logic from commitReconciledScanResultLocked, where the library files
- // needed for dexopt are assigned.
- // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
- // setting needs to be passed to have a comparison, hide it behind an immutable
- // interface. There's no good reason to have 3 different ways to access the real
- // PackageSetting object, only one of which is actually correct.
- PackageSetting realPkgSetting = result.existingSettingCopied
- ? result.request.pkgSetting : result.pkgSetting;
- if (realPkgSetting == null) {
- realPkgSetting = reconciledPkg.pkgSetting;
- }
-
- // Unfortunately, the updated system app flag is only tracked on this PackageSetting
- boolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState()
- .isUpdatedSystemApp();
-
- realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
-
- mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
- null /* instructionSets */,
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.getPackageUseInfoOrDefault(packageName),
- dexoptOptions);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Notify BackgroundDexOptService that the package has been changed.
- // If this is an update of a package which used to fail to compile,
- // BackgroundDexOptService will remove it from its denylist.
- // TODO: Layering violation
- BackgroundDexOptService.notifyPackageChanged(packageName);
-
- notifyPackageChangeObserversOnUpdate(reconciledPkg);
- }
- waitForNativeBinariesExtraction(incrementalStorages);
- }
-
- static void waitForNativeBinariesExtraction(
- ArraySet<IncrementalStorage> incrementalStorages) {
- if (incrementalStorages.isEmpty()) {
- return;
- }
- try {
- // Native library extraction may take very long time: each page could potentially
- // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds
- // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't
- // make much sense as blocking here doesn't lock up the framework, but only blocks
- // the installation session and the following ones.
- Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract");
- for (int i = 0; i < incrementalStorages.size(); ++i) {
- IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i);
- storage.waitForNativeBinariesExtraction();
- }
- } finally {
- Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract");
- }
- }
-
- private int[] getInstalledUsers(PackageSetting ps, int userId) {
- final int[] allUserIds = resolveUserIds(userId);
- final ArrayList<Integer> installedUserIdsList = new ArrayList<>();
- for (int i = 0; i < allUserIds.length; i++) {
- if (ps.getInstalled(allUserIds[i])) {
- installedUserIdsList.add(allUserIds[i]);
- }
- }
- final int numInstalledUserId = installedUserIdsList.size();
- final int[] installedUserIds = new int[numInstalledUserId];
- for (int i = 0; i < numInstalledUserId; i++) {
- installedUserIds[i] = installedUserIdsList.get(i);
- }
- return installedUserIds;
- }
-
- /**
- * Package states callback, used to listen for package state changes and send broadcasts
- */
- private final class IncrementalStatesCallback implements IncrementalStates.Callback {
- private final String mPackageName;
- private final int mUid;
- private final int[] mInstalledUserIds;
- IncrementalStatesCallback(String packageName, int uid, int[] installedUserIds) {
- mPackageName = packageName;
- mUid = uid;
- mInstalledUserIds = installedUserIds;
- }
-
- @Override
- public void onPackageFullyLoaded() {
- final SparseArray<int[]> newBroadcastAllowList;
- final String codePath;
- synchronized (mLock) {
- final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
- if (ps == null) {
- return;
- }
- newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- ps, mInstalledUserIds, mSettings.getPackagesLocked());
- codePath = ps.getPathString();
- }
- // Unregister progress listener
- mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
- // Make sure the information is preserved
- scheduleWriteSettingsLocked();
- }
- }
-
- /**
- * Loading progress callback, used to listen for progress changes and update package setting
- */
- private class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
- private final String mPackageName;
- IncrementalProgressListener(String packageName) {
- mPackageName = packageName;
- }
-
- @Override
- public void onPackageLoadingProgressChanged(float progress) {
- final PackageSetting ps;
- synchronized (mLock) {
- ps = mSettings.getPackageLPr(mPackageName);
- if (ps == null) {
- return;
- }
- ps.setLoadingProgress(progress);
- }
- }
- }
-
@Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid,
int userId) {
final PackageSetting ps;
@@ -20278,914 +17341,33 @@
return ps;
}
- private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
- final PackageSetting pkgSetting = reconciledPkg.pkgSetting;
- final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult;
- final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.removedInfo;
-
- PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
- pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName();
- pkgChangeEvent.version = pkgSetting.versionCode;
- pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime;
- pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.isUpdate);
- pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.dataRemoved);
- pkgChangeEvent.isDeleted = false;
-
- notifyPackageChangeObservers(pkgChangeEvent);
- }
-
private void notifyPackageChangeObserversOnDelete(String packageName, long version) {
- PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
- pkgChangeEvent.packageName = packageName;
- pkgChangeEvent.version = version;
- pkgChangeEvent.lastUpdateTimeMillis = 0L;
- pkgChangeEvent.newInstalled = false;
- pkgChangeEvent.dataRemoved = false;
- pkgChangeEvent.isDeleted = true;
+ PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+ pkgChangeEvent.packageName = packageName;
+ pkgChangeEvent.version = version;
+ pkgChangeEvent.lastUpdateTimeMillis = 0L;
+ pkgChangeEvent.newInstalled = false;
+ pkgChangeEvent.dataRemoved = false;
+ pkgChangeEvent.isDeleted = true;
- notifyPackageChangeObservers(pkgChangeEvent);
+ notifyPackageChangeObservers(pkgChangeEvent);
}
- private void notifyPackageChangeObservers(PackageChangeEvent event) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
- synchronized (mPackageChangeObservers) {
- for(IPackageChangeObserver observer : mPackageChangeObservers) {
- try {
- observer.onPackageChanged(event);
- } catch(RemoteException e) {
- Log.wtf(TAG, e);
- }
- }
- }
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- /**
- * The set of data needed to successfully install the prepared package. This includes data that
- * will be used to scan and reconcile the package.
- */
- private static class PrepareResult {
- public final boolean replace;
- public final int scanFlags;
- public final int parseFlags;
- @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
- public final AndroidPackage existingPackage;
- public final ParsedPackage packageToScan;
- public final boolean clearCodeCache;
- public final boolean system;
- public final PackageSetting originalPs;
- public final PackageSetting disabledPs;
-
- private PrepareResult(boolean replace, int scanFlags,
- int parseFlags, AndroidPackage existingPackage,
- ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
- PackageSetting originalPs, PackageSetting disabledPs) {
- this.replace = replace;
- this.scanFlags = scanFlags;
- this.parseFlags = parseFlags;
- this.existingPackage = existingPackage;
- this.packageToScan = packageToScan;
- this.clearCodeCache = clearCodeCache;
- this.system = system;
- this.originalPs = originalPs;
- this.disabledPs = disabledPs;
- }
- }
-
- private static class PrepareFailure extends PackageManagerException {
-
- public String conflictingPackage;
- public String conflictingPermission;
-
- PrepareFailure(int error) {
- super(error, "Failed to prepare for install.");
- }
-
- PrepareFailure(int error, String detailMessage) {
- super(error, detailMessage);
- }
-
- PrepareFailure(String message, Exception e) {
- super(e instanceof PackageParserException
- ? ((PackageParserException) e).error
- : ((PackageManagerException) e).error,
- ExceptionUtils.getCompleteMessage(message, e));
- }
-
- PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
- String conflictingPackage) {
- this.conflictingPermission = conflictingPermission;
- this.conflictingPackage = conflictingPackage;
- return this;
- }
- }
-
- private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
- @NonNull ParsedPackage parsedPackage, int scanFlags) {
- // If the defining package is signed with our cert, it's okay. This
- // also includes the "updating the same package" case, of course.
- // "updating same package" could also involve key-rotation.
-
- final PackageSetting sourcePackageSetting;
- synchronized (mLock) {
- sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName);
- }
-
- final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
- ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
- final KeySetManagerService ksms = mSettings.getKeySetManagerService();
- if (sourcePackageName.equals(parsedPackage.getPackageName())
- && (ksms.shouldCheckUpgradeKeySetLocked(
- sourcePackageSetting, scanFlags))) {
- return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
- } else {
-
- // in the event of signing certificate rotation, we need to see if the
- // package's certificate has rotated from the current one, or if it is an
- // older certificate with which the current is ok with sharing permissions
- if (sourceSigningDetails.checkCapability(
- parsedPackage.getSigningDetails(),
- SigningDetails.CertCapabilities.PERMISSION)) {
- return true;
- } else if (parsedPackage.getSigningDetails().checkCapability(
- sourceSigningDetails,
- SigningDetails.CertCapabilities.PERMISSION)) {
- // the scanned package checks out, has signing certificate rotation
- // history, and is newer; bring it over
- synchronized (mLock) {
- sourcePackageSetting.signatures.mSigningDetails =
- parsedPackage.getSigningDetails();
+ void notifyPackageChangeObservers(PackageChangeEvent event) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
+ synchronized (mPackageChangeObservers) {
+ for (IPackageChangeObserver observer : mPackageChangeObservers) {
+ try {
+ observer.onPackageChanged(event);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, e);
+ }
}
- return true;
- } else {
- return false;
}
- }
- }
-
- /*
- * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges
- * as this only works for packages that are installed
- *
- * TODO: Move logic for permission group compatibility into PermissionManagerService
- */
- @SuppressWarnings("AndroidFrameworkCompatChange")
- private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) {
- return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S;
- }
-
- @GuardedBy("mInstallLock")
- private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
- throws PrepareFailure {
- final int installFlags = args.installFlags;
- final File tmpPackageFile = new File(args.getCodePath());
- final boolean onExternal = args.volumeUuid != null;
- final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
- final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
- final boolean virtualPreload =
- ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
- final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
- @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
- if (args.move != null) {
- // moving a complete application; perform an initial scan on the new install location
- scanFlags |= SCAN_INITIAL;
- }
- if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
- scanFlags |= SCAN_DONT_KILL_APP;
- }
- if (instantApp) {
- scanFlags |= SCAN_AS_INSTANT_APP;
- }
- if (fullApp) {
- scanFlags |= SCAN_AS_FULL_APP;
- }
- if (virtualPreload) {
- scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
- }
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
-
- // Validity check
- if (instantApp && onExternal) {
- Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
- throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID);
- }
-
- // Retrieve PackageSettings and parse package
- @ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
- | ParsingPackageUtils.PARSE_ENFORCE_CODE
- | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
-
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
- final ParsedPackage parsedPackage;
- try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
- parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
- AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
- } catch (PackageParserException e) {
- throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
-
- // Instant apps have several additional install-time checks.
- if (instantApp) {
- if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
- Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
- + " does not target at least O");
- throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
- "Instant app package must target at least O");
- }
- if (parsedPackage.getSharedUserId() != null) {
- Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
- + " may not declare sharedUserId.");
- throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
- "Instant app package may not declare a sharedUserId");
- }
- }
-
- if (parsedPackage.isStaticSharedLibrary()) {
- // Static shared libraries have synthetic package names
- renameStaticSharedLibraryPackage(parsedPackage);
-
- // No static shared libs on external storage
- if (onExternal) {
- Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
- throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Packages declaring static-shared libs cannot be updated");
- }
- }
-
- String pkgName = res.name = parsedPackage.getPackageName();
- if (parsedPackage.isTestOnly()) {
- if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
- throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
- }
- }
-
- 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 */));
- }
- } catch (PackageParserException e) {
- throw new PrepareFailure("Failed collect during installPackageLI", e);
- }
-
- if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
- < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
- Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
- + " is not signed with at least APK Signature Scheme v2");
- throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
- "Instant app package must be signed with APK Signature Scheme v2 or greater");
- }
-
- boolean systemApp = false;
- boolean replace = false;
- synchronized (mLock) {
- // Check if installing already existing package
- if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
- String oldName = mSettings.getRenamedPackageLPr(pkgName);
- if (parsedPackage.getOriginalPackages().contains(oldName)
- && mPackages.containsKey(oldName)) {
- // This package is derived from an original package,
- // and this device has been updating from that original
- // name. We must continue using the original name, so
- // rename the new package here.
- parsedPackage.setPackageName(oldName);
- pkgName = parsedPackage.getPackageName();
- replace = true;
- if (DEBUG_INSTALL) {
- Slog.d(TAG, "Replacing existing renamed package: oldName="
- + oldName + " pkgName=" + pkgName);
- }
- } else if (mPackages.containsKey(pkgName)) {
- // This package, under its official name, already exists
- // on the device; we should replace it.
- replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
- }
-
- if (replace) {
- // Prevent apps opting out from runtime permissions
- AndroidPackage oldPackage = mPackages.get(pkgName);
- final int oldTargetSdk = oldPackage.getTargetSdkVersion();
- final int newTargetSdk = parsedPackage.getTargetSdkVersion();
- if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
- && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- throw new PrepareFailure(
- PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
- "Package " + parsedPackage.getPackageName()
- + " new target SDK " + newTargetSdk
- + " doesn't support runtime permissions but the old"
- + " target SDK " + oldTargetSdk + " does.");
- }
- // Prevent persistent apps from being updated
- if (oldPackage.isPersistent()
- && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
- throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Package " + oldPackage.getPackageName() + " is a persistent app. "
- + "Persistent apps are not updateable.");
- }
- }
- }
-
- PackageSetting ps = mSettings.getPackageLPr(pkgName);
- if (ps != null) {
- if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
-
- // Static shared libs have same package with different versions where
- // we internally use a synthetic package name to allow multiple versions
- // of the same package, therefore we need to compare signatures against
- // the package setting for the latest library version.
- PackageSetting signatureCheckPs = ps;
- if (parsedPackage.isStaticSharedLibrary()) {
- SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage);
- if (libraryInfo != null) {
- signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
- }
- }
-
- // Quick validity check that we're signed correctly if updating;
- // we'll check this again later when scanning, but we want to
- // bail early here before tripping over redefined permissions.
- final KeySetManagerService ksms = mSettings.getKeySetManagerService();
- if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
- if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
- throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
- + parsedPackage.getPackageName() + " upgrade keys do not match the "
- + "previously installed version");
- }
- } else {
- try {
- final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage);
- final boolean compareRecover = isRecoverSignatureUpdateNeeded(
- parsedPackage);
- // We don't care about disabledPkgSetting on install for now.
- final boolean compatMatch = verifySignatures(signatureCheckPs, null,
- parsedPackage.getSigningDetails(), compareCompat, compareRecover,
- isRollback);
- // The new KeySets will be re-added later in the scanning process.
- if (compatMatch) {
- synchronized (mLock) {
- ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
- }
- }
- } catch (PackageManagerException e) {
- throw new PrepareFailure(e.error, e.getMessage());
- }
- }
-
- if (ps.pkg != null) {
- systemApp = ps.pkg.isSystem();
- }
- res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
- }
-
- final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
- for (int groupNum = 0; groupNum < numGroups; groupNum++) {
- final ParsedPermissionGroup group =
- parsedPackage.getPermissionGroups().get(groupNum);
- final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(group.getName(), 0);
-
- if (sourceGroup != null
- && cannotInstallWithBadPermissionGroups(parsedPackage)) {
- final String sourcePackageName = sourceGroup.packageName;
-
- if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName))
- && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
- scanFlags)) {
- EventLog.writeEvent(0x534e4554, "146211400", -1,
- parsedPackage.getPackageName());
-
- throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP,
- "Package "
- + parsedPackage.getPackageName()
- + " attempting to redeclare permission group "
- + group.getName() + " already owned by "
- + sourcePackageName);
- }
- }
- }
-
- // TODO: Move logic for checking permission compatibility into PermissionManagerService
- final int N = ArrayUtils.size(parsedPackage.getPermissions());
- for (int i = N - 1; i >= 0; i--) {
- final ParsedPermission perm = parsedPackage.getPermissions().get(i);
- final Permission bp = mPermissionManager.getPermissionTEMP(perm.getName());
-
- // Don't allow anyone but the system to define ephemeral permissions.
- if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
- && !systemApp) {
- Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
- + " attempting to delcare ephemeral permission "
- + perm.getName() + "; Removing ephemeral.");
- perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
- }
-
- // Check whether the newly-scanned package wants to define an already-defined perm
- if (bp != null) {
- final String sourcePackageName = bp.getPackageName();
-
- if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
- scanFlags)) {
- // If the owning package is the system itself, we log but allow
- // install to proceed; we fail the install on all other permission
- // redefinitions.
- if (!sourcePackageName.equals("android")) {
- throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
- + parsedPackage.getPackageName()
- + " attempting to redeclare permission "
- + perm.getName() + " already owned by "
- + sourcePackageName)
- .conflictsWithExistingPermission(perm.getName(),
- sourcePackageName);
- } else {
- Slog.w(TAG, "Package " + parsedPackage.getPackageName()
- + " attempting to redeclare system permission "
- + perm.getName() + "; ignoring new declaration");
- parsedPackage.removePermission(i);
- }
- } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
- // Prevent apps to change protection level to dangerous from any other
- // type as this would allow a privilege escalation where an app adds a
- // normal/signature permission in other app's group and later redefines
- // it as dangerous leading to the group auto-grant.
- if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_DANGEROUS) {
- if (bp != null && !bp.isRuntime()) {
- Slog.w(TAG, "Package " + parsedPackage.getPackageName()
- + " trying to change a non-runtime permission "
- + perm.getName()
- + " to runtime; keeping old protection level");
- perm.setProtectionLevel(bp.getProtectionLevel());
- }
- }
- }
- }
-
- if (perm.getGroup() != null
- && cannotInstallWithBadPermissionGroups(parsedPackage)) {
- boolean isPermGroupDefinedByPackage = false;
- for (int groupNum = 0; groupNum < numGroups; groupNum++) {
- if (parsedPackage.getPermissionGroups().get(groupNum).getName()
- .equals(perm.getGroup())) {
- isPermGroupDefinedByPackage = true;
- break;
- }
- }
-
- if (!isPermGroupDefinedByPackage) {
- final PermissionGroupInfo sourceGroup =
- getPermissionGroupInfo(perm.getGroup(), 0);
-
- if (sourceGroup == null) {
- EventLog.writeEvent(0x534e4554, "146211400", -1,
- parsedPackage.getPackageName());
-
- throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
- "Package "
- + parsedPackage.getPackageName()
- + " attempting to declare permission "
- + perm.getName() + " in non-existing group "
- + perm.getGroup());
- } else {
- String groupSourcePackageName = sourceGroup.packageName;
-
- if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName)
- && !doesSignatureMatchForPermissions(groupSourcePackageName,
- parsedPackage, scanFlags)) {
- EventLog.writeEvent(0x534e4554, "146211400", -1,
- parsedPackage.getPackageName());
-
- throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
- "Package "
- + parsedPackage.getPackageName()
- + " attempting to declare permission "
- + perm.getName() + " in group "
- + perm.getGroup() + " owned by package "
- + groupSourcePackageName
- + " with incompatible certificate");
- }
- }
- }
- }
- }
- }
-
- if (systemApp) {
- if (onExternal) {
- // Abort update; system app can't be replaced with app on sdcard
- throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Cannot install updates to system apps on sdcard");
- } else if (instantApp) {
- // Abort update; system app can't be replaced with an instant app
- throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
- "Cannot update a system app with an instant app");
- }
- }
-
- if (args.move != null) {
- // We did an in-place move, so dex is ready to roll
- scanFlags |= SCAN_NO_DEX;
- scanFlags |= SCAN_MOVE;
-
- synchronized (mLock) {
- final PackageSetting ps = mSettings.getPackageLPr(pkgName);
- if (ps == null) {
- res.setError(INSTALL_FAILED_INTERNAL_ERROR,
- "Missing settings for moved package " + pkgName);
- }
-
- // We moved the entire application as-is, so bring over the
- // previously derived ABI information.
- parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
- .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
- }
-
- } else {
- // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
- scanFlags |= SCAN_NO_DEX;
-
- try {
- PackageSetting pkgSetting;
- synchronized (mLock) {
- pkgSetting = mSettings.getPackageLPr(pkgName);
- }
- boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
- && pkgSetting.getPkgState().isUpdatedSystemApp();
- final String abiOverride = deriveAbiOverride(args.abiOverride);
- AndroidPackage oldPackage = mPackages.get(pkgName);
- boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
- final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
- derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
- isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
- abiOverride, mAppLib32InstallDir);
- derivedAbi.first.applyTo(parsedPackage);
- derivedAbi.second.applyTo(parsedPackage);
- } catch (PackageManagerException pme) {
- Slog.e(TAG, "Error deriving application ABI", pme);
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Error deriving application ABI: " + pme.getMessage());
- }
- }
-
- if (!args.doRename(res.returnCode, parsedPackage)) {
- throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
- }
-
- try {
- setUpFsVerityIfPossible(parsedPackage);
- } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to set up verity: " + e);
- }
-
- final PackageFreezer freezer =
- freezePackageForInstall(pkgName, installFlags, "installPackageLI");
- boolean shouldCloseFreezerBeforeReturn = true;
- try {
- final AndroidPackage existingPackage;
- String renamedPackage = null;
- boolean sysPkg = false;
- int targetScanFlags = scanFlags;
- int targetParseFlags = parseFlags;
- final PackageSetting ps;
- final PackageSetting disabledPs;
- if (replace) {
- if (parsedPackage.isStaticSharedLibrary()) {
- // Static libs have a synthetic package name containing the version
- // and cannot be updated as an update would get a new package name,
- // unless this is installed from adb which is useful for development.
- AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName());
- if (existingPkg != null
- && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) {
- throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Packages declaring "
- + "static-shared libs cannot be updated");
- }
- }
-
- final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
-
- final AndroidPackage oldPackage;
- final String pkgName11 = parsedPackage.getPackageName();
- final int[] allUsers;
- final int[] installedUsers;
- final int[] uninstalledUsers;
-
- synchronized (mLock) {
- oldPackage = mPackages.get(pkgName11);
- existingPackage = oldPackage;
- if (DEBUG_INSTALL) {
- Slog.d(TAG,
- "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
- }
-
- ps = mSettings.getPackageLPr(pkgName11);
- disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
-
- // verify signatures are valid
- final KeySetManagerService ksms = mSettings.getKeySetManagerService();
- if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
- if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
- throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "New package not signed by keys specified by upgrade-keysets: "
- + pkgName11);
- }
- } else {
- SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
- SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
- // default to original signature matching
- if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
- SigningDetails.CertCapabilities.INSTALLED_DATA)
- && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
- SigningDetails.CertCapabilities.ROLLBACK)) {
- // Allow the update to proceed if this is a rollback and the parsed
- // package's current signing key is the current signer or in the lineage
- // of the old package; this allows a rollback to a previously installed
- // version after an app's signing key has been rotated without requiring
- // the rollback capability on the previous signing key.
- if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
- parsedPkgSigningDetails)) {
- throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "New package has a different signature: " + pkgName11);
- }
- }
- }
-
- // don't allow a system upgrade unless the upgrade hash matches
- if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
- final byte[] digestBytes;
- try {
- final MessageDigest digest = MessageDigest.getInstance("SHA-512");
- updateDigest(digest, new File(parsedPackage.getBaseApkPath()));
- if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
- for (String path : parsedPackage.getSplitCodePaths()) {
- updateDigest(digest, new File(path));
- }
- }
- digestBytes = digest.digest();
- } catch (NoSuchAlgorithmException | IOException e) {
- throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
- "Could not compute hash: " + pkgName11);
- }
- if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
- throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
- "New package fails restrict-update check: " + pkgName11);
- }
- // retain upgrade restriction
- parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
- }
-
- // Check for shared user id changes
- String invalidPackageName = null;
- if (!Objects.equals(oldPackage.getSharedUserId(),
- parsedPackage.getSharedUserId())) {
- invalidPackageName = parsedPackage.getPackageName();
- }
-
- if (invalidPackageName != null) {
- throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + invalidPackageName + " tried to change user "
- + oldPackage.getSharedUserId());
- }
-
- // In case of rollback, remember per-user/profile install state
- allUsers = mUserManager.getUserIds();
- installedUsers = ps.queryInstalledUsers(allUsers, true);
- uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
-
-
- // don't allow an upgrade from full to ephemeral
- if (isInstantApp) {
- if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
- for (int currentUser : allUsers) {
- if (!ps.getInstantApp(currentUser)) {
- // can't downgrade from full to instant
- Slog.w(TAG,
- "Can't replace full app with instant app: " + pkgName11
- + " for user: " + currentUser);
- throw new PrepareFailure(
- PackageManager.INSTALL_FAILED_SESSION_INVALID);
- }
- }
- } else if (!ps.getInstantApp(args.user.getIdentifier())) {
- // can't downgrade from full to instant
- Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
- + " for user: " + args.user.getIdentifier());
- throw new PrepareFailure(
- PackageManager.INSTALL_FAILED_SESSION_INVALID);
- }
- }
- }
-
- // Update what is removed
- res.removedInfo = new PackageRemovedInfo(this);
- res.removedInfo.uid = oldPackage.getUid();
- res.removedInfo.removedPackage = oldPackage.getPackageName();
- res.removedInfo.installerPackageName = ps.installSource.installerPackageName;
- res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null;
- res.removedInfo.isUpdate = true;
- res.removedInfo.origUsers = installedUsers;
- res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
- for (int i = 0; i < installedUsers.length; i++) {
- final int userId = installedUsers[i];
- res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
- }
- res.removedInfo.uninstallReasons = new SparseArray<>(uninstalledUsers.length);
- for (int i = 0; i < uninstalledUsers.length; i++) {
- final int userId = uninstalledUsers[i];
- res.removedInfo.uninstallReasons.put(userId, ps.getUninstallReason(userId));
- }
-
- sysPkg = oldPackage.isSystem();
- if (sysPkg) {
- // Set the system/privileged/oem/vendor/product flags as needed
- final boolean privileged = oldPackage.isPrivileged();
- final boolean oem = oldPackage.isOem();
- final boolean vendor = oldPackage.isVendor();
- final boolean product = oldPackage.isProduct();
- final boolean odm = oldPackage.isOdm();
- final boolean systemExt = oldPackage.isSystemExt();
- final @ParseFlags int systemParseFlags = parseFlags;
- final @ScanFlags int systemScanFlags = scanFlags
- | SCAN_AS_SYSTEM
- | (privileged ? SCAN_AS_PRIVILEGED : 0)
- | (oem ? SCAN_AS_OEM : 0)
- | (vendor ? SCAN_AS_VENDOR : 0)
- | (product ? SCAN_AS_PRODUCT : 0)
- | (odm ? SCAN_AS_ODM : 0)
- | (systemExt ? SCAN_AS_SYSTEM_EXT : 0);
-
- if (DEBUG_INSTALL) {
- Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
- + ", old=" + oldPackage);
- }
- res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- targetParseFlags = systemParseFlags;
- targetScanFlags = systemScanFlags;
- } else { // non system replace
- replace = true;
- if (DEBUG_INSTALL) {
- Slog.d(TAG,
- "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
- + oldPackage);
- }
- }
- } else { // new package install
- ps = null;
- disabledPs = null;
- replace = false;
- existingPackage = null;
- // Remember this for later, in case we need to rollback this install
- String pkgName1 = parsedPackage.getPackageName();
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
-
- // TODO(patb): MOVE TO RECONCILE
- synchronized (mLock) {
- renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
- if (renamedPackage != null) {
- // A package with the same name is already installed, though
- // it has been renamed to an older name. The package we
- // are trying to install should be installed as an update to
- // the existing one, but that has not been requested, so bail.
- throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
- "Attempt to re-install " + pkgName1
- + " without first uninstalling package running as "
- + renamedPackage);
- }
- if (mPackages.containsKey(pkgName1)) {
- // Don't allow installation over an existing package with the same name.
- throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
- "Attempt to re-install " + pkgName1
- + " without first uninstalling.");
- }
- }
- }
- // we're passing the freezer back to be closed in a later phase of install
- shouldCloseFreezerBeforeReturn = false;
-
- return new PrepareResult(replace, targetScanFlags, targetParseFlags,
- existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
- ps, disabledPs);
- } finally {
- res.freezer = freezer;
- if (shouldCloseFreezerBeforeReturn) {
- freezer.close();
- }
- }
- }
-
- /**
- * Set up fs-verity for the given package if possible. This requires a feature flag of system
- * property to be enabled only if the kernel supports fs-verity.
- *
- * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
- * kernel patches). In normal mode, all file format can be supported.
- */
- private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
- PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
- final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
- final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
- if (!standardMode && !legacyMode) {
- return;
- }
-
- if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion()
- < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) {
- return;
- }
-
- // Collect files we care for fs-verity setup.
- ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
- if (legacyMode) {
- synchronized (mLock) {
- final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
- if (ps != null && ps.isPrivileged()) {
- fsverityCandidates.put(pkg.getBaseApkPath(), null);
- if (pkg.getSplitCodePaths() != null) {
- for (String splitPath : pkg.getSplitCodePaths()) {
- fsverityCandidates.put(splitPath, null);
- }
- }
- }
- }
- } else {
- // NB: These files will become only accessible if the signing key is loaded in kernel's
- // .fs-verity keyring.
- fsverityCandidates.put(pkg.getBaseApkPath(),
- VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath()));
-
- final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
- pkg.getBaseApkPath());
- if (new File(dmPath).exists()) {
- fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
- }
-
- if (pkg.getSplitCodePaths() != null) {
- for (String path : pkg.getSplitCodePaths()) {
- fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
-
- final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
- if (new File(splitDmPath).exists()) {
- fsverityCandidates.put(splitDmPath,
- VerityUtils.getFsveritySignatureFilePath(splitDmPath));
- }
- }
- }
- }
-
- for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
- final String filePath = entry.getKey();
- final String signaturePath = entry.getValue();
-
- if (!legacyMode) {
- // fs-verity is optional for now. Only set up if signature is provided.
- if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
- try {
- VerityUtils.setUpFsverity(filePath, signaturePath);
- } catch (IOException e) {
- throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
- "Failed to enable fs-verity: " + e);
- }
- }
- continue;
- }
-
- // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
- final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
- if (result.isOk()) {
- if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
- final FileDescriptor fd = result.getUnownedFileDescriptor();
- try {
- final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
- try {
- // A file may already have fs-verity, e.g. when reused during a split
- // install. If the measurement succeeds, no need to attempt to set up.
- mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
- } catch (InstallerException e) {
- mInstaller.installApkVerity(filePath, fd, result.getContentSize());
- mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
- }
- } finally {
- IoUtils.closeQuietly(fd);
- }
- } else if (result.isFailed()) {
- throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
- "Failed to generate verity");
- }
- }
- }
-
- private static boolean isExternal(PackageSetting ps) {
- return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
private static boolean isSystemApp(PackageSetting ps) {
@@ -21196,7 +17378,7 @@
return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
+ VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
if (pkg.isExternalStorage()) {
if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
return mSettings.getExternalVersion();
@@ -21436,12 +17618,8 @@
// Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
// uninstall for device owner provisioning.
- if (checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
- == PERMISSION_GRANTED) {
- return true;
- }
-
- return false;
+ return checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+ == PERMISSION_GRANTED;
}
private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
@@ -21599,7 +17777,7 @@
}
}
- info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
+ info.mOrigUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
if (isUpdatedSystemApp(uninstalledPs)
&& ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
@@ -21624,15 +17802,15 @@
try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
deleteFlags, "deletePackageX")) {
res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
- deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
+ deleteFlags | PackageManager.DELETE_CHATTY, info, true);
}
synchronized (mLock) {
if (res) {
if (pkg != null) {
mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs,
- info.removedUsers);
+ info.mRemovedUsers);
}
- updateSequenceNumberLP(uninstalledPs, info.removedUsers);
+ updateSequenceNumberLP(uninstalledPs, info.mRemovedUsers);
updateInstantAppInstallerLocked(packageName);
}
}
@@ -21649,8 +17827,8 @@
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
synchronized (mInstallLock) {
- if (info.args != null) {
- info.args.doPostDeleteLI(true);
+ if (info.mArgs != null) {
+ info.mArgs.doPostDeleteLI(true);
}
boolean reEnableStub = false;
@@ -21702,135 +17880,6 @@
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
- static class PackageRemovedInfo {
- final PackageSender packageSender;
- String removedPackage;
- String installerPackageName;
- int uid = -1;
- int removedAppId = -1;
- int[] origUsers;
- int[] removedUsers = null;
- int[] broadcastUsers = null;
- int[] instantUserIds = null;
- SparseArray<Integer> installReasons;
- SparseArray<Integer> uninstallReasons;
- boolean isRemovedPackageSystemUpdate = false;
- boolean isUpdate;
- boolean dataRemoved;
- boolean removedForAllUsers;
- boolean isStaticSharedLib;
- // a two dimensional array mapping userId to the set of appIds that can receive notice
- // of package changes
- SparseArray<int[]> broadcastAllowList;
- // Clean up resources deleted packages.
- InstallArgs args = null;
-
- PackageRemovedInfo(PackageSender packageSender) {
- this.packageSender = packageSender;
- }
-
- void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
- sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
- }
-
- void sendSystemPackageUpdatedBroadcasts() {
- if (isRemovedPackageSystemUpdate) {
- sendSystemPackageUpdatedBroadcastsInternal();
- }
- }
-
- private void sendSystemPackageUpdatedBroadcastsInternal() {
- Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
- 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
- extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
- packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
- removedPackage, null, null, null, null /* broadcastAllowList */,
- getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
- if (installerPackageName != null) {
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null, null, null /* broadcastAllowList */,
- null);
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null, null, null /* broadcastAllowList */,
- null);
- }
- }
-
- private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
- // Don't send static shared library removal broadcasts as these
- // libs are visible only the the apps that depend on them an one
- // cannot remove the library if it has a dependency.
- if (isStaticSharedLib) {
- return;
- }
- Bundle extras = new Bundle(2);
- final int removedUid = removedAppId >= 0 ? removedAppId : uid;
- extras.putInt(Intent.EXTRA_UID, removedUid);
- extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
- extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
- extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
- if (isUpdate || isRemovedPackageSystemUpdate) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
- if (removedPackage != null) {
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
- removedPackage, extras, 0, null /*targetPackage*/, null,
- broadcastUsers, instantUserIds, broadcastAllowList, null);
- if (installerPackageName != null) {
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
- removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, broadcastUsers, instantUserIds, null, null);
- }
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
- removedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
- null /*finishedReceiver*/, broadcastUsers, instantUserIds,
- broadcastAllowList, null /*bOptions*/);
- if (dataRemoved && !isRemovedPackageSystemUpdate) {
- packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
- removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
- null, broadcastUsers, instantUserIds, broadcastAllowList, null);
- packageSender.notifyPackageRemoved(removedPackage, removedUid);
- }
- }
- if (removedAppId >= 0) {
- // If a system app's updates are uninstalled the UID is not actually removed. Some
- // services need to know the package name affected.
- if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
- extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage);
- }
-
- packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
- null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers, instantUserIds, broadcastAllowList, null);
- }
- }
-
- void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
- removedUsers = userIds;
- if (removedUsers == null) {
- broadcastUsers = null;
- return;
- }
-
- broadcastUsers = EMPTY_INT_ARRAY;
- instantUserIds = EMPTY_INT_ARRAY;
- for (int i = userIds.length - 1; i >= 0; --i) {
- final int userId = userIds[i];
- if (deletedPackageSetting.getInstantApp(userId)) {
- instantUserIds = ArrayUtils.appendInt(instantUserIds, userId);
- } else {
- broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
- }
- }
- }
- }
/*
* This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
@@ -21845,9 +17894,9 @@
// Retrieve object to delete permissions for shared user later on
final AndroidPackage deletedPkg = deletedPs.pkg;
if (outInfo != null) {
- outInfo.removedPackage = packageName;
- outInfo.installerPackageName = deletedPs.installSource.installerPackageName;
- outInfo.isStaticSharedLib = deletedPkg != null
+ outInfo.mRemovedPackage = packageName;
+ outInfo.mInstallerPackageName = deletedPs.installSource.installerPackageName;
+ outInfo.mIsStaticSharedLib = deletedPkg != null
&& deletedPkg.getStaticSharedLibName() != null;
outInfo.populateUsers(deletedPs == null ? null
: deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
@@ -21869,7 +17918,7 @@
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
destroyAppProfilesLIF(resolvedPkg);
if (outInfo != null) {
- outInfo.dataRemoved = true;
+ outInfo.mDataRemoved = true;
}
}
@@ -21886,7 +17935,7 @@
mAppsFilter.removePackage(getPackageSetting(packageName));
removedAppId = mSettings.removePackageLPw(packageName);
if (outInfo != null) {
- outInfo.removedAppId = removedAppId;
+ outInfo.mRemovedAppId = removedAppId;
}
if (!mSettings.isDisabledSystemPackageLPr(packageName)) {
// If we don't have a disabled system package to reinstall, the package is
@@ -21912,12 +17961,12 @@
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
- if (outInfo != null && outInfo.origUsers != null) {
+ if (outInfo != null && outInfo.mOrigUsers != null) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
for (int userId : allUserHandles) {
- final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
+ final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
if (DEBUG_REMOVE) {
Slog.d(TAG, " user " + userId + " => " + installed);
}
@@ -21968,13 +18017,13 @@
@NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
boolean writeSettings)
throws SystemDeleteException {
- final boolean applyUserRestrictions = outInfo != null && (outInfo.origUsers != null);
+ final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
final AndroidPackage deletedPkg = deletedPs.pkg;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
- final PackageSetting disabledPs = action.disabledPs;
+ final PackageSetting disabledPs = action.mDisabledPs;
if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
+ " disabledPs=" + disabledPs);
Slog.d(TAG, "Deleting system pkg from data partition");
@@ -21983,7 +18032,7 @@
if (applyUserRestrictions) {
Slog.d(TAG, "Remembering install states:");
for (int userId : allUserHandles) {
- final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId);
+ final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
Slog.d(TAG, " u=" + userId + " inst=" + finstalled);
}
}
@@ -21991,7 +18040,7 @@
if (outInfo != null) {
// Delete the updated package
- outInfo.isRemovedPackageSystemUpdate = true;
+ outInfo.mIsRemovedPackageSystemUpdate = true;
}
if (disabledPs.versionCode < deletedPs.versionCode) {
@@ -22021,7 +18070,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
- outInfo == null ? null : outInfo.origUsers, writeSettings);
+ outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ e.getMessage());
@@ -22034,8 +18083,8 @@
// and re-enable it afterward.
final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
if (stubPs != null) {
- int userId = action.user == null
- ? UserHandle.USER_ALL : action.user.getIdentifier();
+ int userId = action.mUser == null
+ ? UserHandle.USER_ALL : action.mUser.getIdentifier();
if (userId == UserHandle.USER_ALL) {
for (int aUserId : allUserHandles) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
@@ -22051,7 +18100,7 @@
/**
* Installs a package that's already on the system partition.
*/
- private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
+ private void installPackageFromSystemLIF(@NonNull String codePathString,
@NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
throws PackageManagerException {
final File codePath = new File(codePathString);
@@ -22133,7 +18182,6 @@
writeSettingsLPrTEMP();
}
}
- return pkg;
}
private void deleteInstalledPackageLIF(PackageSetting ps,
@@ -22141,8 +18189,8 @@
PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mLock) {
if (outInfo != null) {
- outInfo.uid = ps.appId;
- outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
+ outInfo.mUid = ps.appId;
+ outInfo.mBroadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
allUserHandles, mSettings.getPackagesLocked());
}
}
@@ -22152,10 +18200,10 @@
// Delete application code and resources only for parent packages
if (deleteCodeAndResources && (outInfo != null)) {
- outInfo.args = createInstallArgsForExisting(
+ outInfo.mArgs = createInstallArgsForExisting(
ps.getPathString(), getAppDexInstructionSets(
ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
+ if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs);
}
}
@@ -22211,23 +18259,6 @@
return true;
}
- private static class DeletePackageAction {
- public final PackageSetting deletingPs;
- public final PackageSetting disabledPs;
- public final PackageRemovedInfo outInfo;
- public final int flags;
- public final UserHandle user;
-
- private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
- PackageRemovedInfo outInfo, int flags, UserHandle user) {
- this.deletingPs = deletingPs;
- this.disabledPs = disabledPs;
- this.outInfo = outInfo;
- this.flags = flags;
- this.user = user;
- }
- }
-
/**
* @return a {@link DeletePackageAction} if the provided package and related state may be
* deleted, {@code null} otherwise.
@@ -22260,8 +18291,7 @@
*/
private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
- PackageRemovedInfo outInfo, boolean writeSettings,
- ParsedPackage replacingPackage) {
+ PackageRemovedInfo outInfo, boolean writeSettings) {
final DeletePackageAction action;
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
@@ -22277,7 +18307,7 @@
try {
executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
- allUserHandles, writeSettings, replacingPackage);
+ allUserHandles, writeSettings);
} catch (SystemDeleteException e) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e);
return false;
@@ -22285,23 +18315,14 @@
return true;
}
- private static class SystemDeleteException extends Exception {
- public final PackageManagerException reason;
-
- private SystemDeleteException(PackageManagerException reason) {
- this.reason = reason;
- }
- }
-
/** Deletes a package. Only throws when install of a disabled package fails. */
- private void executeDeletePackageLIF(DeletePackageAction action,
+ void executeDeletePackageLIF(DeletePackageAction action,
String packageName, boolean deleteCodeAndResources,
- @NonNull int[] allUserHandles, boolean writeSettings,
- ParsedPackage replacingPackage) throws SystemDeleteException {
- final PackageSetting ps = action.deletingPs;
- final PackageRemovedInfo outInfo = action.outInfo;
- final UserHandle user = action.user;
- final int flags = action.flags;
+ @NonNull int[] allUserHandles, boolean writeSettings) throws SystemDeleteException {
+ final PackageSetting ps = action.mDeletingPs;
+ final PackageRemovedInfo outInfo = action.mRemovedInfo;
+ final UserHandle user = action.mUser;
+ final int flags = action.mFlags;
final boolean systemApp = isSystemApp(ps);
// We need to get the permission state before package state is (potentially) destroyed.
@@ -22372,7 +18393,7 @@
// If the package removed had SUSPEND_APPS, unset any restrictions that might have been in
// place for all affected users.
- int[] affectedUserIds = (outInfo != null) ? outInfo.removedUsers : null;
+ int[] affectedUserIds = (outInfo != null) ? outInfo.mRemovedUsers : null;
if (affectedUserIds == null) {
affectedUserIds = resolveUserIds(userId);
}
@@ -22385,7 +18406,7 @@
// Take a note whether we deleted the package for all users
if (outInfo != null) {
- outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+ outInfo.mRemovedForAllUsers = mPackages.get(ps.name) == null;
}
}
@@ -22451,14 +18472,14 @@
if (outInfo != null) {
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- outInfo.dataRemoved = true;
+ outInfo.mDataRemoved = true;
}
- outInfo.removedPackage = ps.name;
- outInfo.installerPackageName = ps.installSource.installerPackageName;
- outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
- outInfo.removedAppId = ps.appId;
- outInfo.removedUsers = userIds;
- outInfo.broadcastUsers = userIds;
+ outInfo.mRemovedPackage = ps.name;
+ outInfo.mInstallerPackageName = ps.installSource.installerPackageName;
+ outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
+ outInfo.mRemovedAppId = ps.appId;
+ outInfo.mRemovedUsers = userIds;
+ outInfo.mBroadcastUsers = userIds;
}
}
@@ -22473,7 +18494,7 @@
try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationProfileData")) {
synchronized (mInstallLock) {
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+ clearAppProfilesLIF(pkg);
}
}
}
@@ -22972,7 +18993,7 @@
}
private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
- int installReason, @UserIdInt int userId) {
+ @UserIdInt int userId) {
// We may also need to apply pending (restored) runtime permission grants
// within these users.
mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
@@ -23513,7 +19534,7 @@
final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
- intent, null, 0, resolveInfos, 0, true, false, false, userId);
+ intent, null, 0, resolveInfos, true, false, false, userId);
final String packageName = preferredResolveInfo != null
&& preferredResolveInfo.activityInfo != null
? preferredResolveInfo.activityInfo.packageName : null;
@@ -23756,18 +19777,6 @@
return packageName;
}
- @Nullable
- private String[] ensureSystemPackageNames(@Nullable String[] packageNames) {
- if (packageNames == null) {
- return null;
- }
- final int packageNamesLength = packageNames.length;
- for (int i = 0; i < packageNamesLength; i++) {
- packageNames[i] = ensureSystemPackageName(packageNames[i]);
- }
- return ArrayUtils.filterNotNull(packageNames, String[]::new);
- }
-
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
@@ -24133,7 +20142,7 @@
+ componentNames);
Bundle extras = new Bundle(4);
extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
- String nameList[] = new String[componentNames.size()];
+ String[] nameList = new String[componentNames.size()];
componentNames.toArray(nameList);
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp);
@@ -24407,11 +20416,7 @@
componentInfo.getComponentName(), userId);
if (componentEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) {
return componentInfo.isEnabled();
- } else if (componentEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) {
- return false;
- }
-
- return true;
+ } else return componentEnabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
} catch (PackageManager.NameNotFoundException ignored) {
return false;
}
@@ -24868,7 +20873,7 @@
ipw.println("Known Packages:");
ipw.increaseIndent();
for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) {
- final String knownPackage = mPmInternal.knownPackageToString(i);
+ final String knownPackage = PackageManagerInternal.knownPackageToString(i);
ipw.print(knownPackage);
ipw.println(":");
final String[] pkgNames = mPmInternal.getKnownPackageNames(i,
@@ -25233,9 +21238,9 @@
//TODO: b/111402650
private void disableSkuSpecificApps() {
- String apkList[] = mContext.getResources().getStringArray(
+ String[] apkList = mContext.getResources().getStringArray(
R.array.config_disableApksUnlessMatchedSku_apk_list);
- String skuArray[] = mContext.getResources().getStringArray(
+ String[] skuArray = mContext.getResources().getStringArray(
R.array.config_disableApkUnlessMatchedSku_skus_list);
if (ArrayUtils.isEmpty(apkList)) {
return;
@@ -25334,32 +21339,6 @@
private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
- private static final String SD_ENCRYPTION_ALGORITHM = "AES";
-
- private boolean mMediaMounted = false;
-
- static String getEncryptKey() {
- try {
- String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
- SD_ENCRYPTION_KEYSTORE_NAME);
- if (sdEncKey == null) {
- sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128,
- SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME);
- if (sdEncKey == null) {
- Slog.e(TAG, "Failed to create encryption keys");
- return null;
- }
- }
- return sdEncKey;
- } catch (NoSuchAlgorithmException nsae) {
- Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
- return null;
- } catch (IOException ioe) {
- Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe);
- return null;
- }
- }
-
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
final int size = packages.size();
@@ -25374,8 +21353,8 @@
finishedReceiver);
}
- private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
- ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+ void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+ ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
sendResourcesChangedBroadcast(mediaStatus, replacing,
pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
}
@@ -25519,7 +21498,7 @@
try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
"unloadPrivatePackagesInner")) {
if (deletePackageLIF(ps.name, null, false, userIds, deleteFlags, outInfo,
- false, null)) {
+ false)) {
unloaded.add(pkg);
} else {
Slog.w(TAG, "Failed to unload " + ps.getPath());
@@ -25776,7 +21755,7 @@
* <p>
* <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
*/
- private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
+ void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
final PackageSetting ps;
synchronized (mLock) {
ps = mSettings.getPackageLPr(pkg.getPackageName());
@@ -25831,9 +21810,9 @@
return prepareAppDataLeaf(batch, pkg, userId, flags);
}
- private @NonNull CompletableFuture<?> prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
+ private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
@NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) {
- return prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
+ prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
// Note: this code block is executed with the Installer lock
// already held, since it's invoked as a side-effect of
// executeBatchLI()
@@ -25886,8 +21865,8 @@
} catch (InstallerException e2) {
logCriticalInfo(Log.DEBUG, "Recovery failed!");
}
- } else if (e != null) {
- Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
+ } else {
+ Slog.e(TAG, "Failed to create app data for " + packageName);
}
// Prepare the application profiles only for upgrades and
@@ -25990,21 +21969,7 @@
}
public PackageFreezer freezePackage(String packageName, int userId, String killReason) {
- return new PackageFreezer(packageName, userId, killReason);
- }
-
- public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
- String killReason) {
- return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
- }
-
- public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
- String killReason) {
- if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
- return new PackageFreezer();
- } else {
- return freezePackage(packageName, userId, killReason);
- }
+ return new PackageFreezer(packageName, userId, killReason, this);
}
public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags,
@@ -26015,74 +21980,13 @@
public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags,
String killReason) {
if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) {
- return new PackageFreezer();
+ return new PackageFreezer(this);
} else {
return freezePackage(packageName, userId, killReason);
}
}
/**
- * Class that freezes and kills the given package upon creation, and
- * unfreezes it upon closing. This is typically used when doing surgery on
- * app code/data to prevent the app from running while you're working.
- */
- private class PackageFreezer implements AutoCloseable {
- private final String mPackageName;
-
- private final boolean mWeFroze;
-
- private final AtomicBoolean mClosed = new AtomicBoolean();
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- /**
- * Create and return a stub freezer that doesn't actually do anything,
- * typically used when someone requested
- * {@link PackageManager#INSTALL_DONT_KILL_APP} or
- * {@link PackageManager#DELETE_DONT_KILL_APP}.
- */
- public PackageFreezer() {
- mPackageName = null;
- mWeFroze = false;
- mCloseGuard.open("close");
- }
-
- public PackageFreezer(String packageName, int userId, String killReason) {
- synchronized (mLock) {
- mPackageName = packageName;
- mWeFroze = mFrozenPackages.add(mPackageName);
-
- final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
- if (ps != null) {
- killApplication(ps.name, ps.appId, userId, killReason);
- }
- }
- mCloseGuard.open("close");
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- mCloseGuard.warnIfOpen();
- close();
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public void close() {
- mCloseGuard.close();
- if (mClosed.compareAndSet(false, true)) {
- synchronized (mLock) {
- if (mWeFroze) {
- mFrozenPackages.remove(mPackageName);
- }
- }
- }
- }
- }
-
- /**
* Verify that given package is currently frozen.
*/
private void checkPackageFrozen(String packageName) {
@@ -26324,23 +22228,14 @@
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
- final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<PackageLite> ret = ApkLiteParseUtils.parsePackageLite(input,
- new File(origin.resolvedPath), /* flags */ 0);
+ new File(origin.mResolvedPath), /* flags */ 0);
final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
- installSource, volumeUuid, user, packageAbiOverride, lite);
- params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
-
- mHandler.sendMessage(msg);
+ installSource, volumeUuid, user, packageAbiOverride, lite, this);
+ params.movePackage();
}
/**
@@ -26356,7 +22251,7 @@
return;
}
- final StorageManager storage = mInjector.getSystemService(StorageManager.class);;
+ final StorageManager storage = mInjector.getSystemService(StorageManager.class);
VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage());
@@ -26606,11 +22501,7 @@
Binder.restoreCallingIdentity(token);
}
final boolean b;
- if (userInfo != null && userInfo.isManagedProfile()) {
- b = true;
- } else {
- b = false;
- }
+ b = userInfo != null && userInfo.isManagedProfile();
mUserNeedsBadging.put(userId, b);
return b;
}
@@ -26727,7 +22618,7 @@
}
}
- private int verifyReplacingVersionCode(PackageInfoLite pkgLite,
+ Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
long requiredInstalledVersionCode, int installFlags) {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
return verifyReplacingVersionCodeForApex(
@@ -26750,18 +22641,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);
}
}
@@ -26771,33 +22666,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
@@ -26805,13 +22704,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);
}
/**
@@ -26823,12 +22723,12 @@
if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
- + before.getLongVersionCode());
+ + before.getLongVersionCode());
} else if (after.getLongVersionCode() == before.getLongVersionCode()) {
if (after.baseRevisionCode < before.getBaseRevisionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update base revision code " + after.baseRevisionCode
- + " is older than current " + before.getBaseRevisionCode());
+ + " is older than current " + before.getBaseRevisionCode());
}
if (!ArrayUtils.isEmpty(after.splitNames)) {
@@ -26839,8 +22739,9 @@
if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update split " + splitName + " revision code "
- + after.splitRevisionCodes[i] + " is older than current "
- + before.getSplitRevisionCodes()[j]);
+ + after.splitRevisionCodes[i]
+ + " is older than current "
+ + before.getSplitRevisionCodes()[j]);
}
}
}
@@ -27059,7 +22960,7 @@
boolean[] results = new boolean[packageNames.length];
for (int i = results.length - 1; i >= 0; --i) {
ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser);
- results[i] = appInfo == null ? false : appInfo.isAudioPlaybackCaptureAllowed();
+ results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
}
return results;
}
@@ -27278,15 +23179,14 @@
@Override
public @Nullable
String getDisabledSystemPackageName(@NonNull String packageName) {
- PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage(
+ PackageSetting disabledPkgSetting = getDisabledSystemPackage(
packageName);
AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
return disabledPkg == null ? null : disabledPkg.getPackageName();
}
/**
- * 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
*
@@ -27427,7 +23327,7 @@
public boolean isPackageSuspended(String packageName, int userId) {
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- return (ps != null) ? ps.getSuspended(userId) : false;
+ return ps != null && ps.getSuspended(userId);
}
}
@@ -27608,7 +23508,7 @@
public boolean isPackageEphemeral(int userId, String packageName) {
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- return ps != null ? ps.getInstantApp(userId) : false;
+ return ps != null && ps.getInstantApp(userId);
}
}
@@ -27836,12 +23736,6 @@
}
@Override
- public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
- return PackageManagerService.this.resolveContentProviderInternal(
- name, flags, userId);
- }
-
- @Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId,
int callingUid) {
return PackageManagerService.this.resolveContentProviderInternal(
@@ -28423,7 +24317,8 @@
}
@Nullable
- public PackageSetting getPackageSetting(String packageName) {
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ PackageSetting getPackageSetting(String packageName) {
return mComputer.getPackageSetting(packageName);
}
@@ -28462,16 +24357,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
*/
@@ -28488,10 +24373,6 @@
processName, uid, seinfo, pid);
}
- public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
- return mCompilerStats.getPackageStats(pkgName);
- }
-
public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
return getOrCreateCompilerPackageStats(pkg.getPackageName());
}
@@ -28500,10 +24381,6 @@
return mCompilerStats.getOrCreatePackageStats(pkgName);
}
- public void deleteCompilerPackageStats(String pkgName) {
- mCompilerStats.deletePackageStats(pkgName);
- }
-
@Override
public boolean isAutoRevokeWhitelisted(String packageName) {
int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow(
@@ -28622,8 +24499,8 @@
public void grantImplicitAccess(int recipientUid, String visibleAuthority) {
// This API is exposed temporarily to only the contacts provider. (b/158688602)
final int callingUid = Binder.getCallingUid();
- ProviderInfo contactsProvider = resolveContentProviderInternal(
- ContactsContract.AUTHORITY, 0, UserHandle.getUserId(callingUid));
+ ProviderInfo contactsProvider = resolveContentProviderInternal(ContactsContract.AUTHORITY,
+ 0, UserHandle.getUserId(callingUid), callingUid);
if (contactsProvider == null || contactsProvider.applicationInfo == null
|| !UserHandle.isSameApp(contactsProvider.applicationInfo.uid, callingUid)) {
throw new SecurityException(callingUid + " is not allow to call grantImplicitAccess");
@@ -28828,7 +24705,7 @@
*
* TODO(zhanghai): This should be removed once we finish migration of permission storage.
*/
- private void writeSettingsLPrTEMP() {
+ void writeSettingsLPrTEMP() {
mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
mSettings.writeLPr();
}
@@ -28986,11 +24863,6 @@
return bOptions;
}
- @NonNull
- public DomainVerificationService.Connection getDomainVerificationConnection() {
- return mDomainVerificationConnection;
- }
-
@Override
public void setKeepUninstalledPackages(List<String> packageList) {
mContext.enforceCallingPermission(
@@ -29093,19 +24965,4 @@
}
}
-interface PackageSender {
- /**
- * @param userIds User IDs where the action occurred on a full application
- * @param instantUserIds User IDs where the action occurred on an instant application
- */
- void sendPackageBroadcast(final String action, final String pkg,
- final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds,
- @Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
- void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
- int dataLoaderType);
- void notifyPackageAdded(String packageName, int uid);
- void notifyPackageChanged(String packageName, int uid);
- void notifyPackageRemoved(String packageName, int uid);
-}
+
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
new file mode 100644
index 0000000..e3581db
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.annotation.NonNull;
+import android.app.ActivityManagerInternal;
+import android.app.BroadcastOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.PowerExemptionManager;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
+
+final class PackageRemovedInfo {
+ final PackageSender mPackageSender;
+ String mRemovedPackage;
+ String mInstallerPackageName;
+ int mUid = -1;
+ int mRemovedAppId = -1;
+ int[] mOrigUsers;
+ int[] mRemovedUsers = null;
+ int[] mBroadcastUsers = null;
+ int[] mInstantUserIds = null;
+ SparseArray<Integer> mInstallReasons;
+ SparseArray<Integer> mUninstallReasons;
+ boolean mIsRemovedPackageSystemUpdate = false;
+ boolean mIsUpdate;
+ boolean mDataRemoved;
+ boolean mRemovedForAllUsers;
+ boolean mIsStaticSharedLib;
+ // a two dimensional array mapping userId to the set of appIds that can receive notice
+ // of package changes
+ SparseArray<int[]> mBroadcastAllowList;
+ // Clean up resources deleted packages.
+ InstallArgs mArgs = null;
+ private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+ PackageRemovedInfo(PackageSender packageSender) {
+ mPackageSender = packageSender;
+ }
+
+ void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
+ sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
+ }
+
+ void sendSystemPackageUpdatedBroadcasts() {
+ if (mIsRemovedPackageSystemUpdate) {
+ sendSystemPackageUpdatedBroadcastsInternal();
+ }
+ }
+
+ private void sendSystemPackageUpdatedBroadcastsInternal() {
+ Bundle extras = new Bundle(2);
+ extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
+ 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
+ extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
+ mRemovedPackage, null, null, null, null /* broadcastAllowList */,
+ getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
+ if (mInstallerPackageName != null) {
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ mRemovedPackage, extras, 0 /*flags*/,
+ mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+ null);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ mRemovedPackage, extras, 0 /*flags*/,
+ mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+ null);
+ }
+ }
+
+ private static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+ @PowerExemptionManager.ReasonCode int reasonCode) {
+ long duration = 10_000;
+ final ActivityManagerInternal amInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+ if (amInternal != null) {
+ duration = amInternal.getBootTimeTempAllowListDuration();
+ }
+ final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
+ bOptions.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ reasonCode, "");
+ return bOptions;
+ }
+
+ private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
+ // Don't send static shared library removal broadcasts as these
+ // libs are visible only the apps that depend on them an one
+ // cannot remove the library if it has a dependency.
+ if (mIsStaticSharedLib) {
+ return;
+ }
+ Bundle extras = new Bundle(2);
+ final int removedUid = mRemovedAppId >= 0 ? mRemovedAppId : mUid;
+ extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
+ extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
+ extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
+ if (mIsUpdate || mIsRemovedPackageSystemUpdate) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
+ if (mRemovedPackage != null) {
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
+ mRemovedPackage, extras, 0, null /*targetPackage*/, null,
+ mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+ if (mInstallerPackageName != null) {
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
+ mRemovedPackage, extras, 0 /*flags*/,
+ mInstallerPackageName, null, mBroadcastUsers, mInstantUserIds, null, null);
+ }
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
+ mRemovedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
+ null /*finishedReceiver*/, mBroadcastUsers, mInstantUserIds,
+ mBroadcastAllowList, null /*bOptions*/);
+ if (mDataRemoved && !mIsRemovedPackageSystemUpdate) {
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
+ mRemovedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
+ null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+ mPackageSender.notifyPackageRemoved(mRemovedPackage, removedUid);
+ }
+ }
+ if (mRemovedAppId >= 0) {
+ // If a system app's updates are uninstalled the UID is not actually removed. Some
+ // services need to know the package name affected.
+ if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
+ }
+
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
+ null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
+ null, null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+ }
+ }
+
+ void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
+ mRemovedUsers = userIds;
+ if (mRemovedUsers == null) {
+ mBroadcastUsers = null;
+ return;
+ }
+
+ mBroadcastUsers = EMPTY_INT_ARRAY;
+ mInstantUserIds = EMPTY_INT_ARRAY;
+ for (int i = userIds.length - 1; i >= 0; --i) {
+ final int userId = userIds[i];
+ if (deletedPackageSetting.getInstantApp(userId)) {
+ mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
+ } else {
+ mBroadcastUsers = ArrayUtils.appendInt(mBroadcastUsers, userId);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java
new file mode 100644
index 0000000..d380098
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageSender.java
@@ -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 com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.IIntentReceiver;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+interface PackageSender {
+ /**
+ * @param userIds User IDs where the action occurred on a full application
+ * @param instantUserIds User IDs where the action occurred on an instant application
+ */
+ void sendPackageBroadcast(String action, String pkg,
+ Bundle extras, int flags, String targetPkg,
+ IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
+ @Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
+ void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
+ int dataLoaderType);
+ void notifyPackageAdded(String packageName, int uid);
+ void notifyPackageChanged(String packageName, int uid);
+ void notifyPackageRemoved(String packageName, int uid);
+}
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index cb9c2e9..a652d1c 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -19,8 +19,6 @@
import android.content.pm.PackageManager;
import android.util.SparseBooleanArray;
-import com.android.server.pm.PackageManagerService.VerificationParams;
-
/**
* Tracks the package verification state for a particular package. Each package verification has a
* required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list
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/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java
new file mode 100644
index 0000000..a54ffa3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PrepareFailure.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.server.pm;
+
+import android.util.ExceptionUtils;
+
+final class PrepareFailure extends PackageManagerException {
+
+ public String mConflictingPackage;
+ public String mConflictingPermission;
+
+ PrepareFailure(int error) {
+ super(error, "Failed to prepare for install.");
+ }
+
+ PrepareFailure(int error, String detailMessage) {
+ super(error, detailMessage);
+ }
+
+ PrepareFailure(String message, Exception e) {
+ super(((PackageManagerException) e).error,
+ ExceptionUtils.getCompleteMessage(message, e));
+ }
+
+ PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
+ String conflictingPackage) {
+ mConflictingPermission = conflictingPermission;
+ mConflictingPackage = conflictingPackage;
+ return this;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java
new file mode 100644
index 0000000..4e08e16
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PrepareResult.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/**
+ * The set of data needed to successfully install the prepared package. This includes data that
+ * will be used to scan and reconcile the package.
+ */
+final class PrepareResult {
+ public final boolean mReplace;
+ public final int mScanFlags;
+ public final int mParseFlags;
+ @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+ public final AndroidPackage mExistingPackage;
+ public final ParsedPackage mPackageToScan;
+ public final boolean mClearCodeCache;
+ public final boolean mSystem;
+ public final PackageSetting mOriginalPs;
+ public final PackageSetting mDisabledPs;
+
+ PrepareResult(boolean replace, int scanFlags,
+ int parseFlags, AndroidPackage existingPackage,
+ ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
+ PackageSetting originalPs, PackageSetting disabledPs) {
+ mReplace = replace;
+ mScanFlags = scanFlags;
+ mParseFlags = parseFlags;
+ mExistingPackage = existingPackage;
+ mPackageToScan = packageToScan;
+ mClearCodeCache = clearCodeCache;
+ mSystem = system;
+ mOriginalPs = originalPs;
+ mDisabledPs = disabledPs;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ReconcileFailure.java b/services/core/java/com/android/server/pm/ReconcileFailure.java
new file mode 100644
index 0000000..c9615ff
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ReconcileFailure.java
@@ -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.server.pm;
+
+final class ReconcileFailure extends PackageManagerException {
+ ReconcileFailure(String message) {
+ super("Reconcile failed: " + message);
+ }
+ ReconcileFailure(int reason, String message) {
+ super(reason, "Reconcile failed: " + message);
+ }
+ ReconcileFailure(PackageManagerException e) {
+ this(e.error, e.getMessage());
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java
new file mode 100644
index 0000000..3188138
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ReconcileRequest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.SharedLibraryInfo;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.utils.WatchedLongSparseArray;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Package scan results and related request details used to reconcile the potential addition of
+ * one or more packages to the system.
+ *
+ * Reconcile will take a set of package details that need to be committed to the system and make
+ * sure that they are valid in the context of the system and the other installing apps. Any
+ * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+ * as install) led to the request.
+ */
+final class ReconcileRequest {
+ public final Map<String, ScanResult> mScannedPackages;
+
+ public final Map<String, AndroidPackage> mAllPackages;
+ public final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> mSharedLibrarySource;
+ public final Map<String, InstallArgs> mInstallArgs;
+ public final Map<String, PackageInstalledInfo> mInstallResults;
+ public final Map<String, PrepareResult> mPreparedPackages;
+ public final Map<String, Settings.VersionInfo> mVersionInfos;
+ public final Map<String, PackageSetting> mLastStaticSharedLibSettings;
+
+ ReconcileRequest(Map<String, ScanResult> scannedPackages,
+ Map<String, InstallArgs> installArgs,
+ Map<String, PackageInstalledInfo> installResults,
+ Map<String, PrepareResult> preparedPackages,
+ Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+ Map<String, AndroidPackage> allPackages,
+ Map<String, Settings.VersionInfo> versionInfos,
+ Map<String, PackageSetting> lastStaticSharedLibSettings) {
+ mScannedPackages = scannedPackages;
+ mInstallArgs = installArgs;
+ mInstallResults = installResults;
+ mPreparedPackages = preparedPackages;
+ mSharedLibrarySource = sharedLibrarySource;
+ mAllPackages = allPackages;
+ mVersionInfos = versionInfos;
+ mLastStaticSharedLibSettings = lastStaticSharedLibSettings;
+ }
+
+ ReconcileRequest(Map<String, ScanResult> scannedPackages,
+ Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+ Map<String, AndroidPackage> allPackages,
+ Map<String, Settings.VersionInfo> versionInfos,
+ Map<String, PackageSetting> lastStaticSharedLibSettings) {
+ this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
+ Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
+ lastStaticSharedLibSettings);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java
new file mode 100644
index 0000000..f78249f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ReconciledPackage.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.util.ArrayMap;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A container of all data needed to commit a package to in-memory data structures and to disk.
+ * TODO: move most of the data contained here into a PackageSetting for commit.
+ */
+final class ReconciledPackage {
+ public final ReconcileRequest mRequest;
+ public final PackageSetting mPkgSetting;
+ public final ScanResult mScanResult;
+ // TODO: Remove install-specific details from the reconcile result
+ public final PackageInstalledInfo mInstallResult;
+ @Nullable public final PrepareResult mPrepareResult;
+ @Nullable public final InstallArgs mInstallArgs;
+ public final DeletePackageAction mDeletePackageAction;
+ public final List<SharedLibraryInfo> mAllowedSharedLibraryInfos;
+ public final SigningDetails mSigningDetails;
+ public final boolean mSharedUserSignaturesChanged;
+ public ArrayList<SharedLibraryInfo> mCollectedSharedLibraryInfos;
+ public final boolean mRemoveAppKeySetData;
+
+ ReconciledPackage(ReconcileRequest request,
+ InstallArgs installArgs,
+ PackageSetting pkgSetting,
+ PackageInstalledInfo installResult,
+ PrepareResult prepareResult,
+ ScanResult scanResult,
+ DeletePackageAction deletePackageAction,
+ List<SharedLibraryInfo> allowedSharedLibraryInfos,
+ SigningDetails signingDetails,
+ boolean sharedUserSignaturesChanged,
+ boolean removeAppKeySetData) {
+ mRequest = request;
+ mInstallArgs = installArgs;
+ mPkgSetting = pkgSetting;
+ mInstallResult = installResult;
+ mPrepareResult = prepareResult;
+ mScanResult = scanResult;
+ mDeletePackageAction = deletePackageAction;
+ mAllowedSharedLibraryInfos = allowedSharedLibraryInfos;
+ mSigningDetails = signingDetails;
+ mSharedUserSignaturesChanged = sharedUserSignaturesChanged;
+ mRemoveAppKeySetData = removeAppKeySetData;
+ }
+
+ /**
+ * Returns a combined set of packages containing the packages already installed combined
+ * with the package(s) currently being installed. The to-be installed packages take
+ * precedence and may shadow already installed packages.
+ */
+ Map<String, AndroidPackage> getCombinedAvailablePackages() {
+ final ArrayMap<String, AndroidPackage> combined =
+ new ArrayMap<>(mRequest.mAllPackages.size() + mRequest.mScannedPackages.size());
+
+ combined.putAll(mRequest.mAllPackages);
+
+ for (ScanResult scanResult : mRequest.mScannedPackages.values()) {
+ combined.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage);
+ }
+
+ return combined;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index e28540c..a7e1a62 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -571,7 +571,7 @@
* In all cases, a return value of null should be interpreted as the apk failing
* to match this Policy instance; i.e. failing this policy stanza.
* </p>
- * @param pkg the apk to check given as a PackageParser.Package object
+ * @param pkg the apk to check given as a AndroidPackage object
* @return A string representing the seinfo matched during policy lookup.
* A value of null can also be returned if no match occured.
*/
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
new file mode 100644
index 0000000..482b79c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/** A package to be scanned */
+@VisibleForTesting
+final class ScanRequest {
+ /** The parsed package */
+ @NonNull public final ParsedPackage mParsedPackage;
+ /** The package this package replaces */
+ @Nullable public final AndroidPackage mOldPkg;
+ /** Shared user settings, if the package has a shared user */
+ @Nullable public final SharedUserSetting mSharedUserSetting;
+ /**
+ * Package settings of the currently installed version.
+ * <p><em>IMPORTANT:</em> The contents of this object may be modified
+ * during scan.
+ */
+ @Nullable public final PackageSetting mPkgSetting;
+ /** A copy of the settings for the currently installed version */
+ @Nullable public final PackageSetting mOldPkgSetting;
+ /** Package settings for the disabled version on the /system partition */
+ @Nullable public final PackageSetting mDisabledPkgSetting;
+ /** Package settings for the installed version under its original package name */
+ @Nullable public final PackageSetting mOriginalPkgSetting;
+ /** The real package name of a renamed application */
+ @Nullable public final String mRealPkgName;
+ public final @ParsingPackageUtils.ParseFlags int mParseFlags;
+ public final @PackageManagerService.ScanFlags int mScanFlags;
+ /** The user for which the package is being scanned */
+ @Nullable public final UserHandle mUser;
+ /** Whether or not the platform package is being scanned */
+ public final boolean mIsPlatformPackage;
+ /** Override value for package ABI if set during install */
+ @Nullable public final String mCpuAbiOverride;
+
+ ScanRequest(
+ @NonNull ParsedPackage parsedPackage,
+ @Nullable SharedUserSetting sharedUserSetting,
+ @Nullable AndroidPackage oldPkg,
+ @Nullable PackageSetting pkgSetting,
+ @Nullable PackageSetting disabledPkgSetting,
+ @Nullable PackageSetting originalPkgSetting,
+ @Nullable String realPkgName,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @PackageManagerService.ScanFlags int scanFlags,
+ boolean isPlatformPackage,
+ @Nullable UserHandle user,
+ @Nullable String cpuAbiOverride) {
+ mParsedPackage = parsedPackage;
+ mOldPkg = oldPkg;
+ mPkgSetting = pkgSetting;
+ mSharedUserSetting = sharedUserSetting;
+ mOldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
+ mDisabledPkgSetting = disabledPkgSetting;
+ mOriginalPkgSetting = originalPkgSetting;
+ mRealPkgName = realPkgName;
+ mParseFlags = parseFlags;
+ mScanFlags = scanFlags;
+ mIsPlatformPackage = isPlatformPackage;
+ mUser = user;
+ mCpuAbiOverride = cpuAbiOverride;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
new file mode 100644
index 0000000..6915a50
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/** The result of a package scan. */
+@VisibleForTesting
+final class ScanResult {
+ /** The request that initiated the scan that produced this result. */
+ public final ScanRequest mRequest;
+ /** Whether or not the package scan was successful */
+ public final boolean mSuccess;
+ /**
+ * Whether or not the original PackageSetting needs to be updated with this result on
+ * commit.
+ */
+ public final boolean mExistingSettingCopied;
+ /**
+ * The final package settings. This may be the same object passed in
+ * the {@link ScanRequest}, but, with modified values.
+ */
+ @Nullable
+ public final PackageSetting mPkgSetting;
+ /** ABI code paths that have changed in the package scan */
+ @Nullable public final List<String> mChangedAbiCodePath;
+
+ public final SharedLibraryInfo mStaticSharedLibraryInfo;
+
+ public final List<SharedLibraryInfo> mDynamicSharedLibraryInfos;
+
+ ScanResult(
+ ScanRequest request, boolean success,
+ @Nullable PackageSetting pkgSetting,
+ @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
+ SharedLibraryInfo staticSharedLibraryInfo,
+ List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
+ mRequest = request;
+ mSuccess = success;
+ mPkgSetting = pkgSetting;
+ mChangedAbiCodePath = changedAbiCodePath;
+ mExistingSettingCopied = existingSettingCopied;
+ mStaticSharedLibraryInfo = staticSharedLibraryInfo;
+ mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 8ddbe08..8bfa728 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -88,7 +88,7 @@
uidFlags = orig.uidFlags;
uidPrivateFlags = orig.uidPrivateFlags;
packages = new ArraySet(orig.packages);
- // A PackageParser.SigningDetails seems to consist solely of final attributes, so
+ // A SigningDetails seems to consist solely of final attributes, so
// it is safe to copy the reference.
signatures.mSigningDetails = orig.signatures.mSigningDetails;
signaturesChanged = orig.signaturesChanged;
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/core/java/com/android/internal/view/InputBindResult.aidl b/services/core/java/com/android/server/pm/SystemDeleteException.java
similarity index 66%
copy from core/java/com/android/internal/view/InputBindResult.aidl
copy to services/core/java/com/android/server/pm/SystemDeleteException.java
index 7ff5c4e..410876f 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/services/core/java/com/android/server/pm/SystemDeleteException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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.
@@ -14,6 +14,12 @@
* limitations under the License.
*/
-package com.android.internal.view;
+package com.android.server.pm;
-parcelable InputBindResult;
+final class SystemDeleteException extends Exception {
+ final PackageManagerException mReason;
+
+ SystemDeleteException(PackageManagerException reason) {
+ mReason = reason;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 190e7bc..0d909a9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2357,6 +2357,9 @@
* {@link #canAddMoreProfilesToUser}.
*/
private boolean canAddMoreUsersOfType(UserTypeDetails userTypeDetails) {
+ if (!userTypeDetails.isEnabled()) {
+ return false;
+ }
final int max = userTypeDetails.getMaxAllowed();
if (max == UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) {
return true; // Indicates that there is no max.
@@ -2397,7 +2400,7 @@
boolean allowedToRemoveOne) {
checkManageUsersPermission("check if more profiles can be added.");
final UserTypeDetails type = mUserTypes.get(userType);
- if (type == null) {
+ if (type == null || !type.isEnabled()) {
return false;
}
// Managed profiles have their own specific rules.
@@ -3553,6 +3556,12 @@
+ ") indicated SYSTEM user, which cannot be created.");
return null;
}
+ if (!userTypeDetails.isEnabled()) {
+ throwCheckedUserOperationException(
+ "Cannot add a user of disabled type " + userType + ".",
+ UserManager.USER_OPERATION_ERROR_MAX_USERS);
+ }
+
synchronized (mUsersLock) {
if (mForceEphemeralUsers) {
flags |= UserInfo.FLAG_EPHEMERAL;
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 6e6d7c3..849d1a338 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -487,7 +487,7 @@
/**
* Gets the system package names that should be installed on users of the given user type, as
* determined by SystemConfig, the allowlist mode, and the apps actually on the device.
- * Names are the {@link PackageParser.Package#packageName}, not necessarily the manifest names.
+ * Names are the {@link AndroidPackage#getPackageName()}, not necessarily the manifest names.
*
* Returns null if all system packages should be installed (due to enforce-mode being off).
*/
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 92ec31b..24dab9e 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -50,7 +50,7 @@
/** Name of the user type, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. */
private final @NonNull String mName;
- // TODO(b/142482943): Currently unused. Hook this up.
+ /** Whether users of this type can be created. */
private final boolean mEnabled;
// TODO(b/142482943): Currently unused and not set. Hook this up.
@@ -195,7 +195,10 @@
return mName;
}
- // TODO(b/142482943) Hook this up or delete it.
+ /**
+ * Returns whether this user type is enabled.
+ * If it is not enabled, all future attempts to create users of this type will be rejected.
+ */
public boolean isEnabled() {
return mEnabled;
}
@@ -390,7 +393,7 @@
private @Nullable Bundle mDefaultSecureSettings = null;
private @Nullable List<DefaultCrossProfileIntentFilter> mDefaultCrossProfileIntentFilters =
null;
- private boolean mEnabled = true;
+ private int mEnabled = 1;
private int mLabel = Resources.ID_NULL;
private @Nullable int[] mBadgeLabels = null;
private @Nullable int[] mBadgeColors = null;
@@ -405,7 +408,7 @@
return this;
}
- public Builder setEnabled(boolean enabled) {
+ public Builder setEnabled(int enabled) {
mEnabled = enabled;
return this;
}
@@ -522,12 +525,25 @@
"UserTypeDetails %s has a non empty "
+ "defaultCrossProfileIntentFilters", mName);
}
- return new UserTypeDetails(mName, mEnabled, mMaxAllowed, mBaseType,
- mDefaultUserInfoPropertyFlags, mLabel, mMaxAllowedPerParent,
- mIconBadge, mBadgePlain, mBadgeNoBackground, mBadgeLabels, mBadgeColors,
+ return new UserTypeDetails(
+ mName,
+ mEnabled != 0,
+ mMaxAllowed,
+ mBaseType,
+ mDefaultUserInfoPropertyFlags,
+ mLabel,
+ mMaxAllowedPerParent,
+ mIconBadge,
+ mBadgePlain,
+ mBadgeNoBackground,
+ mBadgeLabels,
+ mBadgeColors,
mDarkThemeBadgeColors == null ? mBadgeColors : mDarkThemeBadgeColors,
- mDefaultRestrictions, mDefaultSystemSettings, mDefaultSecureSettings,
- mDefaultCrossProfileIntentFilters, mIsMediaSharedWithParent);
+ mDefaultRestrictions,
+ mDefaultSystemSettings,
+ mDefaultSecureSettings,
+ mDefaultCrossProfileIntentFilters,
+ mIsMediaSharedWithParent);
}
private boolean hasBadge() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 30cb40c..5fcb843 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -376,6 +376,8 @@
setResAttribute(parser, "badge-no-background", builder::setBadgeNoBackground);
}
+ setIntAttribute(parser, "enabled", builder::setEnabled);
+
// Process child elements.
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
diff --git a/services/core/java/com/android/server/pm/VerificationInfo.java b/services/core/java/com/android/server/pm/VerificationInfo.java
new file mode 100644
index 0000000..3d4a42c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/VerificationInfo.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.net.Uri;
+
+final class VerificationInfo {
+ /** URI referencing where the package was downloaded from. */
+ final Uri mOriginatingUri;
+
+ /** HTTP referrer URI associated with the originatingURI. */
+ final Uri mReferrer;
+
+ /** UID of the application that the install request originated from. */
+ final int mOriginatingUid;
+
+ /** UID of application requesting the install */
+ final int mInstallerUid;
+
+ VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
+ mOriginatingUri = originatingUri;
+ mReferrer = referrer;
+ mOriginatingUid = originatingUid;
+ mInstallerUid = installerUid;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
new file mode 100644
index 0000000..3c499de
--- /dev/null
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_VERSION_CODE;
+import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
+import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.DataLoaderType;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.VerifierInfo;
+import android.content.pm.parsing.PackageLite;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.server.DeviceIdleInternal;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.io.File;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+final class VerificationParams extends HandlerParams {
+ /**
+ * Whether integrity verification is enabled by default.
+ */
+ private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
+ /**
+ * The default maximum time to wait for the integrity verification to return in
+ * milliseconds.
+ */
+ private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
+ /**
+ * Whether verification is enabled by default.
+ */
+ private static final boolean DEFAULT_VERIFY_ENABLE = true;
+ /**
+ * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+ * rollback within that period, the install will proceed without rollback enabled.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK
+ */
+ private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+ /**
+ * The default duration to wait for rollback to be enabled in
+ * milliseconds.
+ */
+ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
+
+ final OriginInfo mOriginInfo;
+ final IPackageInstallObserver2 mObserver;
+ final int mInstallFlags;
+ @NonNull
+ final InstallSource mInstallSource;
+ final String mPackageAbiOverride;
+ final VerificationInfo mVerificationInfo;
+ final SigningDetails mSigningDetails;
+ @Nullable
+ MultiPackageVerificationParams mParentVerificationParams;
+ final long mRequiredInstalledVersionCode;
+ final int mDataLoaderType;
+ final int mSessionId;
+
+ private boolean mWaitForVerificationToComplete;
+ private boolean mWaitForIntegrityVerificationToComplete;
+ private boolean mWaitForEnableRollbackToComplete;
+ private int mRet = PackageManager.INSTALL_SUCCEEDED;
+ private String mErrorMessage = null;
+
+ final PackageLite mPackageLite;
+ final PackageManagerService mPm;
+
+ VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
+ PackageManagerService pm) {
+ super(user);
+ mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
+ mObserver = observer;
+ mInstallFlags = sessionParams.installFlags;
+ mInstallSource = installSource;
+ mPackageAbiOverride = sessionParams.abiOverride;
+ mVerificationInfo = new VerificationInfo(
+ sessionParams.originatingUri,
+ sessionParams.referrerUri,
+ sessionParams.originatingUid,
+ installerUid
+ );
+ mSigningDetails = signingDetails;
+ mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ mDataLoaderType = (sessionParams.dataLoaderParams != null)
+ ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+ mSessionId = sessionId;
+ mPackageLite = lite;
+ mPm = pm;
+ }
+
+ @Override
+ public String toString() {
+ return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+ + " file=" + mOriginInfo.mFile + "}";
+ }
+
+ public void handleStartCopy() {
+ PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+ mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
+
+ Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+ pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
+ setReturnCode(ret.first, ret.second);
+ if (mRet != INSTALL_SUCCEEDED) {
+ return;
+ }
+
+ // Perform package verification and enable rollback (unless we are simply moving the
+ // package).
+ if (!mOriginInfo.mExisting) {
+ if ((mInstallFlags & PackageManager.INSTALL_APEX) == 0) {
+ // TODO(b/182426975): treat APEX as APK when APK verification is concerned
+ sendApkVerificationRequest(pkgLite);
+ }
+ if ((mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+ sendEnableRollbackRequest();
+ }
+ }
+ }
+
+ void sendApkVerificationRequest(PackageInfoLite pkgLite) {
+ final int verificationId = mPm.mPendingVerificationToken++;
+
+ PackageVerificationState verificationState =
+ new PackageVerificationState(this);
+ mPm.mPendingVerification.append(verificationId, verificationState);
+
+ sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
+ sendPackageVerificationRequest(
+ verificationId, pkgLite, verificationState);
+
+ // If both verifications are skipped, we should remove the state.
+ if (verificationState.areAllVerificationsComplete()) {
+ mPm.mPendingVerification.remove(verificationId);
+ }
+ }
+
+ void sendEnableRollbackRequest() {
+ final int enableRollbackToken = mPm.mPendingEnableRollbackToken++;
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ mPm.mPendingEnableRollback.append(enableRollbackToken, this);
+
+ Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
+ enableRollbackToken);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+ mSessionId);
+ enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
+ enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // Allow the broadcast to be sent before boot complete.
+ // This is needed when committing the apk part of a staged
+ // session in early boot. The rollback manager registers
+ // its receiver early enough during the boot process that
+ // it will not miss the broadcast.
+ enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mPm.mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
+ android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
+
+ mWaitForEnableRollbackToComplete = true;
+
+ // the duration to wait for rollback to be enabled, in millis
+ long rollbackTimeout = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+ DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
+ if (rollbackTimeout < 0) {
+ rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
+ }
+ final Message msg = mPm.mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
+ msg.arg1 = enableRollbackToken;
+ msg.arg2 = mSessionId;
+ mPm.mHandler.sendMessageDelayed(msg, rollbackTimeout);
+ }
+
+ /**
+ * Send a request to check the integrity of the package.
+ */
+ void sendIntegrityVerificationRequest(
+ int verificationId,
+ PackageInfoLite pkgLite,
+ PackageVerificationState verificationState) {
+ if (!isIntegrityVerificationEnabled()) {
+ // Consider the integrity check as passed.
+ verificationState.setIntegrityVerificationResult(
+ PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+ return;
+ }
+
+ final Intent integrityVerification =
+ new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+
+ integrityVerification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
+ PACKAGE_MIME_TYPE);
+
+ final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND;
+ integrityVerification.addFlags(flags);
+
+ integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
+ integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
+ integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
+ integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
+ populateInstallerExtras(integrityVerification);
+
+ // send to integrity component only.
+ integrityVerification.setPackage("android");
+
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+
+ mPm.mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
+ /* receiverPermission= */ null,
+ /* appOp= */ AppOpsManager.OP_NONE,
+ /* options= */ options.toBundle(),
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Message msg =
+ mPm.mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
+ msg.arg1 = verificationId;
+ mPm.mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
+ }
+ }, /* scheduler= */ null,
+ /* initialCode= */ 0,
+ /* initialData= */ null,
+ /* initialExtras= */ null);
+
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
+
+ // stop the copy until verification succeeds.
+ mWaitForIntegrityVerificationToComplete = true;
+ }
+
+
+ /**
+ * Get the integrity verification timeout.
+ *
+ * @return verification timeout in milliseconds
+ */
+ private long getIntegrityVerificationTimeout() {
+ long timeout = Settings.Global.getLong(mPm.mContext.getContentResolver(),
+ Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
+ DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+ // The setting can be used to increase the timeout but not decrease it, since that is
+ // equivalent to disabling the integrity component.
+ return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+ }
+
+ /**
+ * Check whether or not integrity verification has been enabled.
+ */
+ private boolean isIntegrityVerificationEnabled() {
+ // We are not exposing this as a user-configurable setting because we don't want to provide
+ // an easy way to get around the integrity check.
+ return DEFAULT_INTEGRITY_VERIFY_ENABLE;
+ }
+
+ /**
+ * Send a request to verifier(s) to verify the package if necessary.
+ */
+ void sendPackageVerificationRequest(
+ int verificationId,
+ PackageInfoLite pkgLite,
+ PackageVerificationState verificationState) {
+
+ // TODO: http://b/22976637
+ // Apps installed for "all" users use the device owner to verify the app
+ UserHandle verifierUser = getUser();
+ if (verifierUser == UserHandle.ALL) {
+ verifierUser = UserHandle.SYSTEM;
+ }
+
+ /*
+ * Determine if we have any installed package verifiers. If we
+ * do, then we'll defer to them to verify the packages.
+ */
+ final int requiredUid = mPm.mRequiredVerifierPackage == null ? -1
+ : mPm.getPackageUid(mPm.mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ verifierUser.getIdentifier());
+ verificationState.setRequiredVerifierUid(requiredUid);
+ final int installerUid =
+ mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid;
+ final boolean isVerificationEnabled = isVerificationEnabled(
+ pkgLite, verifierUser.getIdentifier(), mInstallFlags, installerUid);
+ final boolean isV4Signed =
+ (mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
+ final boolean isIncrementalInstall =
+ (mDataLoaderType == DataLoaderType.INCREMENTAL);
+ // NOTE: We purposefully skip verification for only incremental installs when there's
+ // a v4 signature block. Otherwise, proceed with verification as usual.
+ if (!mOriginInfo.mExisting
+ && isVerificationEnabled
+ && (!isIncrementalInstall || !isV4Signed)) {
+ final Intent verification = new Intent(
+ Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+ verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
+ PACKAGE_MIME_TYPE);
+ verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // Query all live verifiers based on current user state
+ final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification,
+ PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
+
+ if (DEBUG_VERIFY) {
+ Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent "
+ + verification.toString() + " with " + pkgLite.verifiers.length
+ + " optional verifiers");
+ }
+
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+
+ verification.putExtra(
+ PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags);
+
+ verification.putExtra(
+ PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
+
+ verification.putExtra(
+ PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
+
+ verification.putExtra(
+ PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+ pkgLite.getLongVersionCode());
+
+ populateInstallerExtras(verification);
+
+ final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
+ receivers.getList(), verificationState);
+
+ DeviceIdleInternal idleController =
+ mPm.mInjector.getLocalService(DeviceIdleInternal.class);
+ final long idleDuration = mPm.getVerificationTimeout();
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppAllowlist(idleDuration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_PACKAGE_VERIFIER, "");
+
+ /*
+ * If any sufficient verifiers were listed in the package
+ * manifest, attempt to ask them.
+ */
+ if (sufficientVerifiers != null) {
+ final int n = sufficientVerifiers.size();
+ if (n == 0) {
+ 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);
+ idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+ verifierComponent.getPackageName(), idleDuration,
+ verifierUser.getIdentifier(), false,
+ REASON_PACKAGE_VERIFIER, "package verifier");
+
+ final Intent sufficientIntent = new Intent(verification);
+ sufficientIntent.setComponent(verifierComponent);
+ mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
+ /* receiverPermission= */ null,
+ options.toBundle());
+ }
+ }
+ }
+
+ if (mPm.mRequiredVerifierPackage != null) {
+ final ComponentName requiredVerifierComponent = matchComponentForVerifier(
+ mPm.mRequiredVerifierPackage, receivers.getList());
+ /*
+ * Send the intent to the required verification agent,
+ * but only start the verification timeout after the
+ * target BroadcastReceivers have run.
+ */
+ verification.setComponent(requiredVerifierComponent);
+ idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+ mPm.mRequiredVerifierPackage, idleDuration,
+ verifierUser.getIdentifier(), false,
+ REASON_PACKAGE_VERIFIER, "package verifier");
+ mPm.mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ /* appOp= */ AppOpsManager.OP_NONE,
+ /* options= */ options.toBundle(),
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Message msg = mPm.mHandler
+ .obtainMessage(CHECK_PENDING_VERIFICATION);
+ msg.arg1 = verificationId;
+ mPm.mHandler.sendMessageDelayed(msg, mPm.getVerificationTimeout());
+ }
+ }, null, 0, null, null);
+
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+ /*
+ * We don't want the copy to proceed until verification
+ * succeeds.
+ */
+ mWaitForVerificationToComplete = true;
+ }
+ } else {
+ verificationState.setVerifierResponse(
+ requiredUid, PackageManager.VERIFICATION_ALLOW);
+ }
+ }
+
+
+ private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
+ List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
+ if (pkgInfo.verifiers.length == 0) {
+ return null;
+ }
+
+ final int n = pkgInfo.verifiers.length;
+ final List<ComponentName> sufficientVerifiers = new ArrayList<>(n + 1);
+ for (int i = 0; i < n; i++) {
+ final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
+
+ final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
+ receivers);
+ if (comp == null) {
+ continue;
+ }
+
+ final int verifierUid = getUidForVerifier(verifierInfo);
+ if (verifierUid == -1) {
+ continue;
+ }
+
+ if (DEBUG_VERIFY) {
+ Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
+ + " with the correct signature");
+ }
+ sufficientVerifiers.add(comp);
+ verificationState.addSufficientVerifier(verifierUid);
+ }
+
+ return sufficientVerifiers;
+ }
+
+ private int getUidForVerifier(VerifierInfo verifierInfo) {
+ synchronized (mPm.mLock) {
+ final AndroidPackage pkg = mPm.mPackages.get(verifierInfo.packageName);
+ if (pkg == null) {
+ return -1;
+ } else if (pkg.getSigningDetails().getSignatures().length != 1) {
+ Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ + " has more than one signature; ignoring");
+ return -1;
+ }
+
+ /*
+ * If the public key of the package's signature does not match
+ * our expected public key, then this is a different package and
+ * we should skip.
+ */
+
+ final byte[] expectedPublicKey;
+ try {
+ final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
+ final PublicKey publicKey = verifierSig.getPublicKey();
+ expectedPublicKey = publicKey.getEncoded();
+ } catch (CertificateException e) {
+ return -1;
+ }
+
+ final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
+
+ if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
+ Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ + " does not have the expected public key; ignoring");
+ return -1;
+ }
+
+ return pkg.getUid();
+ }
+ }
+
+ private static ComponentName matchComponentForVerifier(String packageName,
+ List<ResolveInfo> receivers) {
+ ActivityInfo targetReceiver = null;
+
+ final int nr = receivers.size();
+ for (int i = 0; i < nr; i++) {
+ final ResolveInfo info = receivers.get(i);
+ if (info.activityInfo == null) {
+ continue;
+ }
+
+ if (packageName.equals(info.activityInfo.packageName)) {
+ targetReceiver = info.activityInfo;
+ break;
+ }
+ }
+
+ if (targetReceiver == null) {
+ return null;
+ }
+
+ return new ComponentName(targetReceiver.packageName, targetReceiver.name);
+ }
+
+ /**
+ * Check whether or not package verification has been enabled.
+ *
+ * @return true if verification should be performed
+ */
+ private boolean isVerificationEnabled(
+ PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
+ if (!DEFAULT_VERIFY_ENABLE) {
+ return false;
+ }
+
+ // Check if installing from ADB
+ if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
+ if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
+ return true;
+ }
+ // Check if the developer wants to skip verification for ADB installs
+ if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+ synchronized (mPm.mLock) {
+ if (mPm.mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
+ // Always verify fresh install
+ return true;
+ }
+ }
+ // Only skip when apk is debuggable
+ return !pkgInfoLite.debuggable;
+ }
+ return Settings.Global.getInt(mPm.mContext.getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
+ }
+
+ // only when not installed from ADB, skip verification for instant apps when
+ // the installer and verifier are the same.
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ if (mPm.mInstantAppInstallerActivity != null
+ && mPm.mInstantAppInstallerActivity.packageName.equals(
+ mPm.mRequiredVerifierPackage)) {
+ try {
+ mPm.mInjector.getSystemService(AppOpsManager.class)
+ .checkPackage(installerUid, mPm.mRequiredVerifierPackage);
+ if (DEBUG_VERIFY) {
+ Slog.i(TAG, "disable verification for instant app");
+ }
+ return false;
+ } catch (SecurityException ignore) { }
+ }
+ }
+ return true;
+ }
+
+ void populateInstallerExtras(Intent intent) {
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
+ mInstallSource.initiatingPackageName);
+
+ if (mVerificationInfo != null) {
+ if (mVerificationInfo.mOriginatingUri != null) {
+ intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
+ mVerificationInfo.mOriginatingUri);
+ }
+ if (mVerificationInfo.mReferrer != null) {
+ intent.putExtra(Intent.EXTRA_REFERRER,
+ mVerificationInfo.mReferrer);
+ }
+ if (mVerificationInfo.mOriginatingUid >= 0) {
+ intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
+ mVerificationInfo.mOriginatingUid);
+ }
+ if (mVerificationInfo.mInstallerUid >= 0) {
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
+ mVerificationInfo.mInstallerUid);
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+
+ void handleVerificationFinished() {
+ mWaitForVerificationToComplete = false;
+ handleReturnCode();
+ }
+
+ void handleIntegrityVerificationFinished() {
+ mWaitForIntegrityVerificationToComplete = false;
+ handleReturnCode();
+ }
+
+
+ void handleRollbackEnabled() {
+ // TODO(b/112431924): Consider halting the install if we
+ // couldn't enable rollback.
+ mWaitForEnableRollbackToComplete = false;
+ handleReturnCode();
+ }
+
+ @Override
+ void handleReturnCode() {
+ if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
+ || mWaitForEnableRollbackToComplete) {
+ return;
+ }
+ sendVerificationCompleteNotification();
+ }
+
+ private void sendVerificationCompleteNotification() {
+ if (mParentVerificationParams != null) {
+ mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
+ } else {
+ try {
+ mObserver.onPackageInstalled(null, mRet, mErrorMessage,
+ new Bundle());
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ public void verifyStage() {
+ mPm.mHandler.post(this::startCopy);
+ }
+
+ public void verifyStage(List<VerificationParams> children)
+ throws PackageManagerException {
+ final MultiPackageVerificationParams params =
+ new MultiPackageVerificationParams(this, children);
+ mPm.mHandler.post(params::startCopy);
+ }
+
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ static final class MultiPackageVerificationParams extends HandlerParams {
+ private final IPackageInstallObserver2 mObserver;
+ private final List<VerificationParams> mChildParams;
+ private final Map<VerificationParams, Integer> mVerificationState;
+
+ MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children)
+ throws PackageManagerException {
+ super(parent.getUser());
+ if (children.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = children;
+ // Provide every child with reference to this object as parent
+ for (int i = 0; i < children.size(); i++) {
+ final VerificationParams childParams = children.get(i);
+ childParams.mParentVerificationParams = this;
+ }
+ mVerificationState = new ArrayMap<>(mChildParams.size());
+ mObserver = parent.mObserver;
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (VerificationParams params : mChildParams) {
+ params.handleStartCopy();
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (VerificationParams params : mChildParams) {
+ params.handleReturnCode();
+ }
+ }
+
+ void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
+ mVerificationState.put(child, currentStatus);
+ if (mVerificationState.size() != mChildParams.size()) {
+ return;
+ }
+ int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+ 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,
+ errorMsg, new Bundle());
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+}
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..f467a7f 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -22,8 +22,6 @@
import android.app.ActivityThread;
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 +37,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;
@@ -47,7 +46,7 @@
import java.util.List;
/**
- * The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
+ * The v2 of package parsing for use when parsing is initiated in the server and must
* contain state contained by the server.
*
* The {@link AutoCloseable} helps signal that this class contains resources that must be freed.
@@ -147,7 +146,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 +158,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/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 4bbe373..dd50b0c 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -33,6 +33,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.PermissionThread;
/**
* Class that handles one-time permissions for a user
@@ -79,7 +80,8 @@
mContext = context;
mActivityManager = context.getSystemService(ActivityManager.class);
mAlarmManager = context.getSystemService(AlarmManager.class);
- mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
+ mPermissionControllerManager = new PermissionControllerManager(
+ mContext, PermissionThread.getHandler());
mHandler = context.getMainThreadHandler();
}
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..919ed5f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -145,6 +145,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.PermissionThread;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
@@ -2056,7 +2057,7 @@
private byte[] backupRuntimePermissions(@UserIdInt int userId) {
CompletableFuture<byte[]> backup = new CompletableFuture<>();
mPermissionControllerManager.getRuntimePermissionBackup(UserHandle.of(userId),
- mContext.getMainExecutor(), backup::complete);
+ PermissionThread.getExecutor(), backup::complete);
try {
return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
@@ -2101,7 +2102,7 @@
}
}
mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName,
- UserHandle.of(userId), mContext.getMainExecutor(), (hasMoreBackup) -> {
+ UserHandle.of(userId), PermissionThread.getExecutor(), (hasMoreBackup) -> {
if (hasMoreBackup) {
return;
}
@@ -3348,13 +3349,15 @@
}
@Override
- public void registerAttributionSource(@NonNull AttributionSource source) {
- mAttributionSourceRegistry.registerAttributionSource(source);
+ public void registerAttributionSource(@NonNull AttributionSourceState source) {
+ mAttributionSourceRegistry
+ .registerAttributionSource(new AttributionSource(source));
}
@Override
- public boolean isRegisteredAttributionSource(@NonNull AttributionSource source) {
- return mAttributionSourceRegistry.isRegisteredAttributionSource(source);
+ public boolean isRegisteredAttributionSource(@NonNull AttributionSourceState source) {
+ return mAttributionSourceRegistry
+ .isRegisteredAttributionSource(new AttributionSource(source));
}
@Override
@@ -3385,7 +3388,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 "
@@ -4548,7 +4551,8 @@
}
}
- mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
+ mPermissionControllerManager = new PermissionControllerManager(
+ mContext, PermissionThread.getHandler());
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index fad0aef..ef21543 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -31,8 +31,7 @@
import java.util.stream.Collectors;
/**
- * For use by {@link PackageSetting} to maintain functionality that used to exist in
- * {@link PackageParser.Package}.
+ * For use by {@link PackageSetting} to maintain functionality that used to exist in PackageParser.
*
* It is assumed that anything inside the package was not cached or written to disk, so none of
* these fields are either. They must be set on every boot from other state on the device.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index ad43514..2709d4f 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -64,8 +64,8 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.PermissionThread;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -279,7 +279,7 @@
PermissionControllerManager manager = mPermControllerManagers.get(user);
if (manager == null) {
manager = new PermissionControllerManager(
- getUserContext(getContext(), user), FgThread.getHandler());
+ getUserContext(getContext(), user), PermissionThread.getHandler());
mPermControllerManagers.put(user, manager);
}
manager.updateUserSensitiveForApp(uid);
@@ -287,8 +287,9 @@
}, UserHandle.ALL, intentFilter, null, null);
PermissionControllerManager manager = new PermissionControllerManager(
- getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler());
- FgThread.getHandler().postDelayed(manager::updateUserSensitive,
+ getUserContext(getContext(), Process.myUserHandle()),
+ PermissionThread.getHandler());
+ PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
USER_SENSITIVE_UPDATE_DELAY_MS);
}
@@ -315,7 +316,7 @@
if (isStarted(changedUserId)) {
synchronized (mLock) {
if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
- FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService
::synchronizePackagePermissionsAndAppOpsForUser,
this, packageName, changedUserId));
@@ -421,9 +422,9 @@
final PermissionControllerManager permissionControllerManager =
new PermissionControllerManager(
getUserContext(getContext(), UserHandle.of(userId)),
- FgThread.getHandler());
+ PermissionThread.getHandler());
permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
- FgThread.getExecutor(), successful -> {
+ PermissionThread.getExecutor(), successful -> {
if (successful) {
future.complete(null);
} else {
@@ -527,7 +528,7 @@
synchronized (mLock) {
if (!mIsUidSyncScheduled.get(uid)) {
mIsUidSyncScheduled.put(uid, true);
- FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
this, uid));
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e7636fc..75b66b3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3029,7 +3029,8 @@
@Override
public void onKeyguardOccludedChangedLw(boolean occluded) {
- if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()
+ && !WindowManagerService.sEnableShellTransitions) {
mPendingKeyguardOccluded = occluded;
mKeyguardOccludedChanged = true;
} else {
@@ -3853,9 +3854,13 @@
}
mCameraGestureTriggered = false;
final MutableBoolean outLaunched = new MutableBoolean(false);
- mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
+ final boolean intercept =
+ mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
if (!outLaunched.value) {
- return false;
+ // If GestureLauncherService intercepted the power key, but didn't launch camera app,
+ // we should still return the intercept result. This prevents the single key gesture
+ // detector from processing the power key later on.
+ return intercept;
}
mCameraGestureTriggered = true;
if (mRequestedOrSleepingDefaultDisplay) {
@@ -4255,6 +4260,7 @@
pmWakeReason)) + ")");
}
+ mActivityTaskManagerInternal.notifyWakingUp();
mDefaultDisplayPolicy.setAwake(true);
// Since goToSleep performs these functions synchronously, we must
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 855a1cc..051f555 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -276,4 +276,4 @@
public void dump(String prefix, PrintWriter pw) {
mKeyguardStateMonitor.dump(prefix, pw);
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7555a7f..c91d8de 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -96,6 +96,7 @@
private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4;
private static final int MSG_PROFILE_TIMED_OUT = 5;
private static final int MSG_WIRED_CHARGING_STARTED = 6;
+ private static final int MSG_SCREEN_POLICY = 7;
private static final long[] CHARGING_VIBRATION_TIME = {
40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
@@ -120,6 +121,7 @@
private final SuspendBlocker mSuspendBlocker;
private final WindowManagerPolicy mPolicy;
private final FaceDownDetector mFaceDownDetector;
+ private final ScreenUndimDetector mScreenUndimDetector;
private final ActivityManagerInternal mActivityManagerInternal;
private final InputManagerInternal mInputManagerInternal;
private final InputMethodManagerInternal mInputMethodManagerInternal;
@@ -167,13 +169,14 @@
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- FaceDownDetector faceDownDetector) {
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
mContext = context;
mBatteryStats = batteryStats;
mAppOps = mContext.getSystemService(AppOpsManager.class);
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mFaceDownDetector = faceDownDetector;
+ mScreenUndimDetector = screenUndimDetector;
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
@@ -620,6 +623,22 @@
}
/**
+ * Called when the screen policy changes.
+ */
+ public void onScreenPolicyUpdate(int newPolicy) {
+ if (DEBUG) {
+ Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy);
+ }
+
+ synchronized (mLock) {
+ Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY);
+ msg.arg1 = newPolicy;
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
* Dumps data for bugreports.
*
* @param pw The stream to print to.
@@ -659,6 +678,7 @@
tm.notifyUserActivity();
mPolicy.userActivity();
mFaceDownDetector.userActivity(event);
+ mScreenUndimDetector.userActivity();
}
void postEnhancedDischargePredictionBroadcast(long delayMs) {
@@ -812,6 +832,10 @@
mSuspendBlocker.release();
}
+ private void screenPolicyChanging(int screenPolicy) {
+ mScreenUndimDetector.recordScreenPolicy(screenPolicy);
+ }
+
private void lockProfile(@UserIdInt int userId) {
mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
}
@@ -852,6 +876,9 @@
case MSG_WIRED_CHARGING_STARTED:
showWiredChargingStarted(msg.arg1);
break;
+ case MSG_SCREEN_POLICY:
+ screenPolicyChanging(msg.arg1);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c39b5da..218ab78 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -273,6 +273,7 @@
private final BatterySavingStats mBatterySavingStats;
private final AttentionDetector mAttentionDetector;
private final FaceDownDetector mFaceDownDetector;
+ private final ScreenUndimDetector mScreenUndimDetector;
private final BinderService mBinderService;
private final LocalService mLocalService;
private final NativeWrapper mNativeWrapper;
@@ -837,9 +838,10 @@
static class Injector {
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- FaceDownDetector faceDownDetector) {
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
return new Notifier(
- looper, context, batteryStats, suspendBlocker, policy, faceDownDetector);
+ looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
+ screenUndimDetector);
}
SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -960,6 +962,7 @@
mInjector.createAmbientDisplaySuppressionController(context);
mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
mFaceDownDetector = new FaceDownDetector(this::onFlip);
+ mScreenUndimDetector = new ScreenUndimDetector();
mBatterySavingStats = new BatterySavingStats(mLock);
mBatterySaverPolicy =
@@ -1152,7 +1155,7 @@
mBatteryStats = BatteryStatsService.getService();
mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
- mPolicy, mFaceDownDetector);
+ mPolicy, mFaceDownDetector, mScreenUndimDetector);
mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
mInjector.createSuspendBlocker(
@@ -1187,6 +1190,7 @@
mBatterySaverController.systemReady();
mBatterySaverPolicy.systemReady();
mFaceDownDetector.systemReady(mContext);
+ mScreenUndimDetector.systemReady(mContext);
// Register for settings changes.
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -3192,6 +3196,7 @@
final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
displayPowerRequest, mRequestWaitForNegativeProximity);
+ mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy);
if (DEBUG_SPEW) {
Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java
new file mode 100644
index 0000000..951bc1f
--- /dev/null
+++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen
+ * on temporarily (without changing the screen timeout setting).
+ */
+public class ScreenUndimDetector {
+ private static final String TAG = "ScreenUndimDetector";
+ private static final boolean DEBUG = false;
+
+ private static final String UNDIM_DETECTOR_WAKE_LOCK = "UndimDetectorWakeLock";
+
+ /** DeviceConfig flag: is keep screen on feature enabled. */
+ static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled";
+ private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true;
+ private static final int OUTCOME_POWER_BUTTON =
+ FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON;
+ private static final int OUTCOME_TIMEOUT =
+ FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__TIMEOUT;
+ private boolean mKeepScreenOnEnabled;
+
+ /** DeviceConfig flag: how long should we keep the screen on. */
+ @VisibleForTesting
+ static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis";
+ @VisibleForTesting
+ static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10);
+ private long mKeepScreenOnForMillis;
+
+ /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */
+ @VisibleForTesting
+ static final String KEY_UNDIMS_REQUIRED = "undims_required";
+ @VisibleForTesting
+ static final int DEFAULT_UNDIMS_REQUIRED = 2;
+ private int mUndimsRequired;
+
+ /**
+ * DeviceConfig flag: what is the maximum duration between undims to still consider them
+ * consecutive.
+ */
+ @VisibleForTesting
+ static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS =
+ "max_duration_between_undims_millis";
+ @VisibleForTesting
+ static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5);
+ private long mMaxDurationBetweenUndimsMillis;
+
+ @VisibleForTesting
+ PowerManager.WakeLock mWakeLock;
+
+ @VisibleForTesting
+ int mCurrentScreenPolicy;
+ @VisibleForTesting
+ int mUndimCounter = 0;
+ @VisibleForTesting
+ long mUndimCounterStartedMillis;
+ private long mUndimOccurredTime = -1;
+ private long mInteractionAfterUndimTime = -1;
+ private InternalClock mClock;
+
+ public ScreenUndimDetector() {
+ mClock = new InternalClock();
+ }
+
+ ScreenUndimDetector(InternalClock clock) {
+ mClock = clock;
+ }
+
+ static class InternalClock {
+ public long getCurrentTime() {
+ return SystemClock.elapsedRealtime();
+ }
+ }
+
+ /** Should be called in parent's systemReady() */
+ public void systemReady(Context context) {
+ readValuesFromDeviceConfig();
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ context.getMainExecutor(),
+ (properties) -> onDeviceConfigChange(properties.getKeyset()));
+
+ final PowerManager powerManager = context.getSystemService(PowerManager.class);
+ mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
+ | PowerManager.ON_AFTER_RELEASE,
+ UNDIM_DETECTOR_WAKE_LOCK);
+ }
+
+ /**
+ * Launches a message that figures out the screen transitions and detects user undims. Must be
+ * called by the parent that is trying to update the screen policy.
+ */
+ public void recordScreenPolicy(int newPolicy) {
+ if (newPolicy == mCurrentScreenPolicy) {
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Screen policy transition: " + mCurrentScreenPolicy + " -> " + newPolicy);
+ }
+
+ // update the current policy with the new one immediately so we don't accidentally get
+ // into a loop (which is possible if the switch below triggers a new policy).
+ final int currentPolicy = mCurrentScreenPolicy;
+ mCurrentScreenPolicy = newPolicy;
+
+ if (!mKeepScreenOnEnabled) {
+ return;
+ }
+
+ switch (currentPolicy) {
+ case POLICY_DIM:
+ if (newPolicy == POLICY_BRIGHT) {
+ final long now = mClock.getCurrentTime();
+ final long timeElapsedSinceFirstUndim = now - mUndimCounterStartedMillis;
+ if (timeElapsedSinceFirstUndim >= mMaxDurationBetweenUndimsMillis) {
+ reset();
+ }
+ if (mUndimCounter == 0) {
+ mUndimCounterStartedMillis = now;
+ }
+
+ mUndimCounter++;
+
+ if (DEBUG) {
+ Slog.d(TAG, "User undim, counter=" + mUndimCounter
+ + " (required=" + mUndimsRequired + ")"
+ + ", timeElapsedSinceFirstUndim=" + timeElapsedSinceFirstUndim
+ + " (max=" + mMaxDurationBetweenUndimsMillis + ")");
+ }
+ if (mUndimCounter >= mUndimsRequired) {
+ reset();
+ if (DEBUG) {
+ Slog.d(TAG, "Acquiring a wake lock for " + mKeepScreenOnForMillis);
+ }
+ if (mWakeLock != null) {
+ mUndimOccurredTime = mClock.getCurrentTime();
+ mWakeLock.acquire(mKeepScreenOnForMillis);
+ }
+ }
+ } else {
+ if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+ checkAndLogUndim(OUTCOME_TIMEOUT);
+ }
+ reset();
+ }
+ break;
+ case POLICY_BRIGHT:
+ if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+ checkAndLogUndim(OUTCOME_POWER_BUTTON);
+ }
+ if (newPolicy != POLICY_DIM) {
+ reset();
+ }
+ break;
+ }
+ }
+
+ @VisibleForTesting
+ void reset() {
+ if (DEBUG) {
+ Slog.d(TAG, "Resetting the undim detector");
+ }
+ mUndimCounter = 0;
+ mUndimCounterStartedMillis = 0;
+ if (mWakeLock != null && mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+
+ private boolean readKeepScreenOnNotificationEnabled() {
+ return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_KEEP_SCREEN_ON_ENABLED,
+ DEFAULT_KEEP_SCREEN_ON_ENABLED);
+ }
+
+ private long readKeepScreenOnForMillis() {
+ return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_KEEP_SCREEN_ON_FOR_MILLIS,
+ DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS);
+ }
+
+ private int readUndimsRequired() {
+ int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ DEFAULT_UNDIMS_REQUIRED);
+
+ if (undimsRequired < 1 || undimsRequired > 5) {
+ Slog.e(TAG, "Provided undimsRequired=" + undimsRequired
+ + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED);
+ return DEFAULT_UNDIMS_REQUIRED;
+ }
+
+ return undimsRequired;
+ }
+
+ private long readMaxDurationBetweenUndimsMillis() {
+ return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+ DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS);
+ }
+
+ private void onDeviceConfigChange(@NonNull Set<String> keys) {
+ for (String key : keys) {
+ Slog.i(TAG, "onDeviceConfigChange; key=" + key);
+ switch (key) {
+ case KEY_KEEP_SCREEN_ON_ENABLED:
+ case KEY_KEEP_SCREEN_ON_FOR_MILLIS:
+ case KEY_UNDIMS_REQUIRED:
+ case KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS:
+ readValuesFromDeviceConfig();
+ return;
+ default:
+ Slog.i(TAG, "Ignoring change on " + key);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void readValuesFromDeviceConfig() {
+ mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled();
+ mKeepScreenOnForMillis = readKeepScreenOnForMillis();
+ mUndimsRequired = readUndimsRequired();
+ mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis();
+
+ Slog.i(TAG, "readValuesFromDeviceConfig():"
+ + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis
+ + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled
+ + "\nmUndimsRequired=" + mUndimsRequired);
+
+ }
+
+ /**
+ * The user interacted with the screen after an undim, indicating the phone is in use.
+ * We use this event for logging.
+ */
+ public void userActivity() {
+ if (mUndimOccurredTime != 1 && mInteractionAfterUndimTime == -1) {
+ mInteractionAfterUndimTime = mClock.getCurrentTime();
+ }
+ }
+
+ /**
+ * Checks and logs if an undim occurred.
+ *
+ * A log will occur if an undim seems to have resulted in a timeout or a direct screen off such
+ * as from a power button. Some outcomes may not be correctly assigned to a
+ * TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME value.
+ */
+ private void checkAndLogUndim(int outcome) {
+ if (mUndimOccurredTime != -1) {
+ long now = mClock.getCurrentTime();
+ FrameworkStatsLog.write(FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED,
+ outcome,
+ /* time_to_outcome_millis=*/ now - mUndimOccurredTime,
+ /* time_to_first_interaction_millis= */
+ mInteractionAfterUndimTime != -1 ? now - mInteractionAfterUndimTime : -1
+ );
+ mUndimOccurredTime = -1;
+ mInteractionAfterUndimTime = -1;
+ }
+ }
+}
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/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index d95e826..cdab91b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -22,8 +22,8 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -133,7 +133,7 @@
/** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */
void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName);
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName);
/** @see com.android.internal.statusbar.IStatusBar#showTransient */
void showTransient(int displayId, @InternalInsetsType int[] types);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 47fdc4e..ff7e903 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -59,8 +59,8 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -527,13 +527,14 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
if (mBar != null) {
try {
mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, requestedState, packageName);
+ navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
} catch (RemoteException ex) { }
}
}
@@ -1110,7 +1111,7 @@
private final ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
private boolean mNavbarColorManagedByIme = false;
private @Behavior int mBehavior;
- private InsetsState mRequestedState = new InsetsState();
+ private InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -1121,12 +1122,13 @@
private void setBarAttributes(@Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsState requestedState, String packageName) {
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities,
+ String packageName) {
mAppearance = appearance;
mAppearanceRegions = appearanceRegions;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mRequestedState = requestedState;
+ mRequestedVisibilities = requestedVisibilities;
mPackageName = packageName;
}
@@ -1247,7 +1249,7 @@
state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
state.mImeBackDisposition, state.mShowImeSwitcher,
gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
- state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedState,
+ state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedVisibilities,
state.mPackageName, transientBarTypes);
}
}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index fe977f8..ac2d76e 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -28,8 +28,10 @@
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ServiceConfigAccessor;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
@@ -63,6 +65,7 @@
KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
})
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@Retention(RetentionPolicy.SOURCE)
@interface DeviceConfigKey {}
@@ -72,40 +75,39 @@
* {@link ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupportedInConfig()} and {@link
* ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupported()}.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
+ public static final @DeviceConfigKey String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
"location_time_zone_detection_feature_supported";
/**
* The key for the server flag that can override the device config for whether the primary
* location time zone provider is enabled, disabled, or (for testing) in simulation mode.
*/
- @DeviceConfigKey
- public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
"primary_location_time_zone_provider_mode_override";
/**
* The key for the server flag that can override the device config for whether the secondary
* location time zone provider is enabled or disabled, or (for testing) in simulation mode.
*/
- @DeviceConfigKey
- public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
"secondary_location_time_zone_provider_mode_override";
/**
* The key for the minimum delay after location time zone detection has been enabled before the
* location time zone manager can report it is uncertain about the time zone.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
"location_time_zone_detection_uncertainty_delay_millis";
/**
* The key for the timeout passed to a location time zone provider that tells it how long it has
* to provide an explicit first suggestion without being declared uncertain.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
"ltpz_init_timeout_millis";
/**
@@ -113,8 +115,8 @@
* #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
* manager before the location time zone provider will actually be declared uncertain.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
"ltpz_init_timeout_fuzz_millis";
/**
@@ -123,16 +125,16 @@
* disable the feature by turning off the master location switch, or by disabling automatic time
* zone detection.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
"location_time_zone_detection_setting_enabled_override";
/**
* The key for the default value used to determine whether location time zone detection is
* enabled when the user hasn't explicitly set it yet.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
"location_time_zone_detection_setting_enabled_default";
/**
@@ -140,16 +142,14 @@
* of strings that will be passed to {@link TimeDetectorStrategy#stringToOrigin(String)}.
* All values must be recognized or the override value will be ignored.
*/
- @DeviceConfigKey
- public static final String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE =
+ public static final @DeviceConfigKey String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE =
"time_detector_origin_priorities_override";
/**
* The key to override the time detector lower bound configuration. The values is the number of
* milliseconds since the beginning of the Unix epoch.
*/
- @DeviceConfigKey
- public static final String KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE =
+ public static final @DeviceConfigKey String KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE =
"time_detector_lower_bound_millis_override";
@GuardedBy("mListeners")
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index ff5060e..acabb6e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -53,24 +53,19 @@
@interface Origin {}
/** Used when a time value originated from a telephony signal. */
- @Origin
- int ORIGIN_TELEPHONY = 1;
+ @Origin int ORIGIN_TELEPHONY = 1;
/** Used when a time value originated from a user / manual settings. */
- @Origin
- int ORIGIN_MANUAL = 2;
+ @Origin int ORIGIN_MANUAL = 2;
/** Used when a time value originated from a network signal. */
- @Origin
- int ORIGIN_NETWORK = 3;
+ @Origin int ORIGIN_NETWORK = 3;
/** Used when a time value originated from a gnss signal. */
- @Origin
- int ORIGIN_GNSS = 4;
+ @Origin int ORIGIN_GNSS = 4;
/** Used when a time value originated from an externally specified signal. */
- @Origin
- int ORIGIN_EXTERNAL = 5;
+ @Origin int ORIGIN_EXTERNAL = 5;
/** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index 27b50d8..9eb6a45 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -26,6 +26,10 @@
import android.util.proto.ProtoOutputStream;
import java.io.ByteArrayOutputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -44,14 +48,13 @@
@IntDef(prefix = "DETECTION_MODE_",
value = { DETECTION_MODE_MANUAL, DETECTION_MODE_GEO, DETECTION_MODE_TELEPHONY})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface DetectionMode {};
- @DetectionMode
- public static final int DETECTION_MODE_MANUAL = 0;
- @DetectionMode
- public static final int DETECTION_MODE_GEO = 1;
- @DetectionMode
- public static final int DETECTION_MODE_TELEPHONY = 2;
+ public static final @DetectionMode int DETECTION_MODE_MANUAL = 0;
+ public static final @DetectionMode int DETECTION_MODE_GEO = 1;
+ public static final @DetectionMode int DETECTION_MODE_TELEPHONY = 2;
@NonNull
private final ConfigurationInternal mConfigurationInternal;
@@ -132,8 +135,7 @@
* Returns the detection mode the device is currently using, which can be influenced by various
* things besides the user's setting.
*/
- @DetectionMode
- public int getDetectionMode() {
+ public @DetectionMode int getDetectionMode() {
if (!mConfigurationInternal.getAutoDetectionEnabledBehavior()) {
return DETECTION_MODE_MANUAL;
} else if (mConfigurationInternal.getGeoDetectionEnabledBehavior()) {
diff --git a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
index 5087530..dfefb8f 100644
--- a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
+++ b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
@@ -33,7 +33,7 @@
class OrdinalGenerator<T> {
private final ArraySet<T> mKnownIds = new ArraySet<>();
- private final @NonNull Function<T, T> mCanonicalizationFunction;
+ @NonNull private final Function<T, T> mCanonicalizationFunction;
OrdinalGenerator(@NonNull Function<T, T> canonicalizationFunction) {
mCanonicalizationFunction = Objects.requireNonNull(canonicalizationFunction);
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 23f6bbe..2be8e35 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -48,7 +48,7 @@
@StringDef(prefix = "PROVIDER_MODE_",
value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
@Retention(RetentionPolicy.SOURCE)
- @Target(ElementType.TYPE_USE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface ProviderMode {}
/**
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index c2add2d..c0fd6b1 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -48,6 +48,10 @@
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
import com.android.server.timezonedetector.location.ThreadingDomain.SingleRunnableQueue;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -101,34 +105,36 @@
value = { PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_STARTED_INITIALIZING,
PROVIDER_STATE_STARTED_CERTAIN, PROVIDER_STATE_STARTED_UNCERTAIN,
PROVIDER_STATE_STOPPED, PROVIDER_STATE_PERM_FAILED, PROVIDER_STATE_DESTROYED })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface ProviderStateEnum {}
/**
* Uninitialized value. Must not be used afte {@link LocationTimeZoneProvider#initialize}.
*/
- static final int PROVIDER_STATE_UNKNOWN = 0;
+ static final @ProviderStateEnum int PROVIDER_STATE_UNKNOWN = 0;
/**
* The provider is started and has not reported its first event.
*/
- static final int PROVIDER_STATE_STARTED_INITIALIZING = 1;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_INITIALIZING = 1;
/**
* The provider is started and most recently reported a "suggestion" event.
*/
- static final int PROVIDER_STATE_STARTED_CERTAIN = 2;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_CERTAIN = 2;
/**
* The provider is started and most recently reported an "uncertain" event.
*/
- static final int PROVIDER_STATE_STARTED_UNCERTAIN = 3;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_UNCERTAIN = 3;
/**
* The provider is stopped.
*
* This is the state after {@link #initialize} is called.
*/
- static final int PROVIDER_STATE_STOPPED = 4;
+ static final @ProviderStateEnum int PROVIDER_STATE_STOPPED = 4;
/**
* The provider has failed and cannot be restarted. This is a terminated state triggered by
@@ -136,16 +142,16 @@
*
* Providers may enter this state any time after a provider is started.
*/
- static final int PROVIDER_STATE_PERM_FAILED = 5;
+ static final @ProviderStateEnum int PROVIDER_STATE_PERM_FAILED = 5;
/**
* The provider has been destroyed by the controller and cannot be restarted. Similar to
* {@link #PROVIDER_STATE_PERM_FAILED} except that a provider is set into this state.
*/
- static final int PROVIDER_STATE_DESTROYED = 6;
+ static final @ProviderStateEnum int PROVIDER_STATE_DESTROYED = 6;
/** The {@link LocationTimeZoneProvider} the state is for. */
- public final @NonNull LocationTimeZoneProvider provider;
+ @NonNull public final LocationTimeZoneProvider provider;
/** The state enum value of the current state. */
public final @ProviderStateEnum int stateEnum;
diff --git a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
index 3e224e0..7648795 100644
--- a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
+++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
@@ -22,6 +22,10 @@
import android.service.timezone.TimeZoneProviderService;
import android.service.timezone.TimeZoneProviderSuggestion;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.Objects;
/**
@@ -31,31 +35,32 @@
@IntDef(prefix = "EVENT_TYPE_",
value = { EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUGGESTION, EVENT_TYPE_UNCERTAIN })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
public @interface EventType {}
/**
* The provider failed permanently. See {@link
* TimeZoneProviderService#reportPermanentFailure(Throwable)}
*/
- public static final int EVENT_TYPE_PERMANENT_FAILURE = 1;
+ public static final @EventType int EVENT_TYPE_PERMANENT_FAILURE = 1;
/**
* The provider made a suggestion. See {@link
* TimeZoneProviderService#reportSuggestion(TimeZoneProviderSuggestion)}
*/
- public static final int EVENT_TYPE_SUGGESTION = 2;
+ public static final @EventType int EVENT_TYPE_SUGGESTION = 2;
/**
* The provider was uncertain about the time zone. See {@link
* TimeZoneProviderService#reportUncertain()}
*/
- public static final int EVENT_TYPE_UNCERTAIN = 3;
+ public static final @EventType int EVENT_TYPE_UNCERTAIN = 3;
private static final TimeZoneProviderEvent UNCERTAIN_EVENT =
new TimeZoneProviderEvent(EVENT_TYPE_UNCERTAIN, null, null);
- @EventType
- private final int mType;
+ private final @EventType int mType;
@Nullable
private final TimeZoneProviderSuggestion mSuggestion;
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 4e453f3..fd1995d 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -695,7 +695,7 @@
// Both direct boot aware and unaware packages are fine as we
// will do filtering at query time to avoid multiple parsing.
final ProviderInfo pi = getProviderInfo(uri.getAuthority(), sourceUserId,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, SYSTEM_UID);
if (pi != null && sourcePkg.equals(pi.packageName)) {
int targetUid = mPmInternal.getPackageUid(
targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
@@ -759,9 +759,10 @@
if (DEBUG) Slog.v(TAG,
"Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
+ // Unchecked call, passing the system's uid as the calling uid to the getProviderInfo
final String authority = grantUri.uri.getAuthority();
final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId,
- MATCH_DEBUG_TRIAGED_MISSING);
+ MATCH_DEBUG_TRIAGED_MISSING, SYSTEM_UID);
if (pi == null) {
Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString());
return;
@@ -812,7 +813,7 @@
final String authority = grantUri.uri.getAuthority();
final ProviderInfo pi = getProviderInfo(authority, grantUri.sourceUserId,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid);
if (pi == null) {
Slog.w(TAG, "No content provider found for permission revoke: "
+ grantUri.toSafeString());
@@ -1056,11 +1057,6 @@
}
}
- private ProviderInfo getProviderInfo(String authority, int userHandle, int pmFlags) {
- return mPmInternal.resolveContentProvider(authority,
- PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userHandle);
- }
-
private ProviderInfo getProviderInfo(String authority, int userHandle, int pmFlags,
int callingUid) {
return mPmInternal.resolveContentProvider(authority,
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 3c0a05b..450257f 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -195,6 +195,7 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int SAFEMODE_TIMEOUT_SECONDS = 30;
+ private static final int SAFEMODE_TIMEOUT_SECONDS_TEST_MODE = 10;
private interface EventInfo {}
@@ -1082,7 +1083,9 @@
createScheduledAlarm(
SAFEMODE_TIMEOUT_ALARM,
delayedMessage,
- TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ mVcnContext.isInTestMode()
+ ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE)
+ : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
}
private void cancelSafeModeAlarm() {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 26d6374..372d3ec 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -75,7 +75,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;
@@ -95,7 +94,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;
@@ -178,17 +176,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(
@@ -198,30 +191,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);
@@ -238,10 +216,8 @@
throw new IllegalStateException(errorMessage);
}
}
- removeObserversForEmbeddedChildDisplays(windowsForA11yObserver);
mWindowsForAccessibilityObserver.remove(displayId);
}
- return true;
}
void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
@@ -508,54 +484,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",
@@ -585,23 +513,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.
*/
@@ -1535,8 +1446,6 @@
private final long mRecurringAccessibilityEventsIntervalMillis;
- private final IntArray mEmbeddedDisplayIdList = new IntArray(0);
-
// Set to true if initializing window population complete.
private boolean mInitialized;
@@ -1574,28 +1483,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(),
@@ -1762,12 +1649,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,
@@ -1971,8 +1853,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 97804d9..331b8de 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1042,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);
@@ -1182,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;
@@ -1194,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;
@@ -1204,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 3d99836..d0578a3 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;
@@ -2825,7 +2826,7 @@
/**
* @return Whether AppOps allows this package to enter picture-in-picture.
*/
- private boolean checkEnterPictureInPictureAppOpsState() {
+ boolean checkEnterPictureInPictureAppOpsState() {
return mAtmService.getAppOpsManager().checkOpNoThrow(
OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
}
@@ -3445,10 +3446,20 @@
return;
}
finishing = true;
+ final TaskFragment taskFragment = getTaskFragment();
+ if (taskFragment != null) {
+ taskFragment.sendTaskFragmentInfoChanged();
+ }
if (stopped) {
abortAndClearOptionsAnimation();
}
- mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+ if (mAtmService.getTransitionController().isCollecting()) {
+ // We don't want the finishing to change the transition ready state since there will not
+ // be corresponding setReady for finishing.
+ mAtmService.getTransitionController().collectExistenceChange(this);
+ } else {
+ mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+ }
}
/**
@@ -4315,6 +4326,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(
@@ -4327,6 +4340,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(
@@ -4366,6 +4381,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(),
@@ -4416,7 +4432,8 @@
}
if (options != null) {
- mAtmService.getTransitionController().setOverrideAnimation(options);
+ mAtmService.getTransitionController().setOverrideAnimation(options,
+ startCallback, finishCallback);
}
}
@@ -5145,6 +5162,12 @@
void notifyAppStopped() {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
+ // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
+ // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
+ // Clear any surface transactions and content overlay in this case.
+ if (task != null && task.mLastRecentsAnimationTransaction != null) {
+ task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
+ }
// Reset the last saved PiP snap fraction on app stop.
mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
@@ -9054,7 +9077,7 @@
record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
- record.mStartBounds, task.getTaskInfo());
+ record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
}
@Override
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 f161f12..395b25d 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_PERMISSION_DENIED;
import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
import static android.app.ActivityManager.START_SUCCESS;
@@ -193,7 +194,6 @@
private Task mTargetTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
- private boolean mKeepCurTransition;
private boolean mAvoidMoveToFront;
private boolean mFrozeTaskList;
private boolean mTransientLaunch;
@@ -592,7 +592,6 @@
mTargetRootTask = starter.mTargetRootTask;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
- mKeepCurTransition = starter.mKeepCurTransition;
mAvoidMoveToFront = starter.mAvoidMoveToFront;
mFrozeTaskList = starter.mFrozeTaskList;
@@ -744,7 +743,7 @@
Slog.w(TAG, "Unable to find app for caller " + mRequest.caller + " (pid="
+ mRequest.callingPid + ") when starting: " + mRequest.intent.toString());
SafeActivityOptions.abort(mRequest.activityOptions);
- return ActivityManager.START_PERMISSION_DENIED;
+ return START_PERMISSION_DENIED;
}
}
@@ -858,7 +857,7 @@
} else {
Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
+ ") when starting: " + intent.toString());
- err = ActivityManager.START_PERMISSION_DENIED;
+ err = START_PERMISSION_DENIED;
}
}
@@ -1559,6 +1558,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 +1584,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 +1600,7 @@
mSupervisor.mUserLeaving = false;
// Transition housekeeping
- if (!ActivityManager.isStartResultSuccessful(result)) {
+ if (!startResultSuccessful) {
if (newTransition != null) {
newTransition.abort();
}
@@ -1697,6 +1706,8 @@
mIntent.setFlags(mLaunchFlags);
+ // Get top task at beginning because the order may be changed when reusing existing task.
+ final Task prevTopTask = mPreferredTaskDisplayArea.getFocusedRootTask();
final Task reusedTask = getReusableTask();
// If requested, freeze the task list
@@ -1755,11 +1766,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.
@@ -1781,24 +1787,23 @@
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
}
+ final Task startedTask = mStartActivity.getTask();
if (newTask) {
- EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
- mStartActivity.getTask().mTaskId);
+ EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);
}
- mStartActivity.logStartActivity(
- EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
+ mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
mStartActivity.getTaskFragment().clearLastPausedActivity();
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
+ final boolean isTaskSwitch = startedTask != prevTopTask;
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
- mKeepCurTransition, mOptions, sourceRecord);
+ isTaskSwitch, mOptions, sourceRecord);
if (mDoResume) {
- final ActivityRecord topTaskActivity =
- mStartActivity.getTask().topRunningActivityLocked();
+ final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
@@ -1832,8 +1837,8 @@
mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
// Update the recent tasks list immediately when the activity starts
- mSupervisor.mRecentTasks.add(mStartActivity.getTask());
- mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
+ mSupervisor.mRecentTasks.add(startedTask);
+ mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);
return START_SUCCESS;
@@ -1947,10 +1952,41 @@
}
}
+ if (mInTaskFragment != null && mInTaskFragment.getTask() != null) {
+ final int hostUid = mInTaskFragment.getTask().effectiveUid;
+ final int embeddingUid = targetTask != null ? targetTask.effectiveUid : r.getUid();
+ if (!canTaskBeEmbedded(hostUid, embeddingUid)) {
+ Slog.e(TAG, "Cannot embed activity to a task owned by " + hostUid + " targetTask= "
+ + targetTask);
+ return START_PERMISSION_DENIED;
+ }
+ }
+
return START_SUCCESS;
}
/**
+ * Return {@code true} if the {@param task} can embed another task.
+ * @param hostUid the uid of the host task
+ * @param embeddedUid the uid of the task the are going to be embedded
+ */
+ private boolean canTaskBeEmbedded(int hostUid, int embeddedUid) {
+ // Allowing the embedding if the task is owned by system.
+ if (hostUid == Process.SYSTEM_UID) {
+ return true;
+ }
+
+ // Allowing embedding if the host task is owned by an app that has the ACTIVITY_EMBEDDING
+ // permission
+ if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, hostUid) == PERMISSION_GRANTED) {
+ return true;
+ }
+
+ // Allowing embedding if it is from the same app that owned the task
+ return hostUid == embeddedUid;
+ }
+
+ /**
* Prepare the target task to be reused for this launch, which including:
* - Position the target task on valid root task on preferred display.
* - Comply to the specified activity launch flags
@@ -2241,7 +2277,6 @@
mTargetTask = null;
mMovedToFront = false;
mNoAnimation = false;
- mKeepCurTransition = false;
mAvoidMoveToFront = false;
mFrozeTaskList = false;
mTransientLaunch = false;
@@ -2731,31 +2766,6 @@
mIntentDelivered = true;
}
- /**
- * Return {@code true} if the {@param task} has child {@code TaskFragment}s and the
- * {@param activity} can be embedded in. Otherwise, return {@code false}
- */
- private boolean canActivityBeEmbedded(@NonNull ActivityRecord activity, @NonNull Task task) {
- if (task.isLeafTaskFragment()) {
- return false;
- }
-
- final int taskUid = task.effectiveUid;
- // Allowing the activity be embedded into leaf TaskFragment if the task is owned by system.
- if (taskUid == Process.SYSTEM_UID) {
- return true;
- }
-
- // Allowing embedding if the task is owned by an app that has the ACTIVITY_EMBEDDING
- // permission
- if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, taskUid) == PERMISSION_GRANTED) {
- return true;
- }
-
- // Allowing embedding if the activity is from the same app that owned the task
- return activity.isUid(taskUid);
- }
-
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task;
if (mInTaskFragment != null) {
@@ -2767,7 +2777,7 @@
} else {
newParent = mInTaskFragment;
}
- } else if (canActivityBeEmbedded(mStartActivity, task)) {
+ } else {
// Use the child TaskFragment (if any) as the new parent if the activity can be embedded
final ActivityRecord top = task.topRunningActivity();
newParent = top != null ? top.getTaskFragment() : task;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 1759cde..5174a38 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -621,4 +621,7 @@
*/
public abstract boolean hasSystemAlertWindowPermission(int callingUid, int callingPid,
String callingPackage);
+
+ /** Called when the device is waking up */
+ public abstract void notifyWakingUp();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 48a6626..25827cf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -64,6 +64,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_WAKE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -6500,6 +6501,13 @@
return ActivityTaskManagerService.this.hasSystemAlertWindowPermission(callingUid,
callingPid, callingPackage);
}
+
+ @Override
+ public void notifyWakingUp() {
+ // Start a transition for waking. This is needed for showWhenLocked activities.
+ getTransitionController().requestTransitionIfNeeded(TRANSIT_WAKE, 0 /* flags */,
+ null /* trigger */, mRootWindowContainer.getDefaultDisplay());
+ }
}
final class PackageConfigurationUpdaterImpl implements
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index f6cca84..cb9c037 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;
}
@@ -1534,7 +1551,13 @@
return;
}
if (task.isVisible()) {
- mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ if (mService.getTransitionController().isCollecting()) {
+ // We don't want the finishing to change the transition ready state since there will
+ // not be corresponding setReady for finishing.
+ mService.getTransitionController().collectExistenceChange(task);
+ } else {
+ mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ }
} else {
// Removing a non-visible task doesn't require a transition, but if there is one
// collecting, this should be a member just in case.
@@ -2270,14 +2293,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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fef82ac..c6b92c0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -61,6 +61,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
@@ -132,7 +133,6 @@
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
@@ -197,6 +197,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.MagnificationSpec;
import android.view.PrivacyIndicatorBounds;
import android.view.RemoteAnimationDefinition;
@@ -293,6 +294,22 @@
*/
private final SurfaceControl mWindowingLayer;
+ /**
+ * The window token of the layer of the hierarchy to mirror, or null if this DisplayContent
+ * is not being used for layer mirroring.
+ */
+ @VisibleForTesting IBinder mTokenToMirror = null;
+
+ /**
+ * The surface for mirroring the contents of this hierarchy.
+ */
+ private SurfaceControl mMirroredSurface = null;
+
+ /**
+ * The last bounds of the DisplayArea to mirror.
+ */
+ private Rect mLastMirroredDisplayAreaBounds = null;
+
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
@@ -428,6 +445,7 @@
// Accessed directly by all users.
private boolean mLayoutNeeded;
int pendingLayoutChanges;
+ boolean mLayoutAndAssignWindowLayersScheduled;
/**
* Used to gate application window layout until we have sent the complete configuration.
@@ -500,11 +518,6 @@
WindowState mCurrentFocus = null;
/**
- * The last focused window that we've notified the client that the focus is changed.
- */
- WindowState mLastFocus = null;
-
- /**
* The foreground app of this display. Windows below this app cannot be the focused window. If
* the user taps on the area outside of the task of the focused app, we will notify AM about the
* new task the user wants to interact with.
@@ -731,12 +744,19 @@
// When switching the app task, we keep the IME window visibility for better
// transitioning experiences.
- // However, in case IME created a child window without dismissing during the task
- // switching to keep the window focus because IME window has higher window hierarchy,
- // we don't give it focus if the next IME layering target doesn't request IME visible.
- if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
+ // However, in case IME created a child window or the IME selection dialog without
+ // dismissing during the task switching to keep the window focus because IME window has
+ // higher window hierarchy, we don't give it focus if the next IME layering target
+ // doesn't request IME visible.
+ if (w.mIsImWindow && (mImeLayeringTarget == null
|| !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
- return false;
+ if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ return false;
+ }
+
+ if (w.isChildWindow()) {
+ return false;
+ }
}
final ActivityRecord activity = w.mActivityRecord;
@@ -1107,6 +1127,10 @@
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+ // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring
+ // to capture the contents of a DisplayArea.
+ startMirrorIfNeeded();
}
boolean isReady() {
@@ -1237,12 +1261,6 @@
// removing from parent.
token.getParent().removeChild(token);
}
- if (token.hasChild(prevDc.mLastFocus)) {
- // If the reparent window token contains previous display's last focus window, means
- // it will end up to gain window focus on the target display, so it should not be
- // notified that it lost focus from the previous display.
- prevDc.mLastFocus = null;
- }
}
addWindowToken(token.token, token);
@@ -2467,6 +2485,25 @@
// Update IME parent if needed.
updateImeParent();
+ // Update mirroring surface for MediaProjection, if this DisplayContent is being used
+ // for layer mirroring.
+ if (mMirroredSurface != null) {
+ // Retrieve the size of the DisplayArea to mirror, and continue with the update if the
+ // bounds have changed.
+ final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+ mTokenToMirror);
+ if (wc != null && mLastMirroredDisplayAreaBounds != null) {
+ // Retrieve the size of the DisplayArea to mirror, and continue with the update
+ // if the bounds or orientation has changed.
+ final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
+ int displayAreaOrientation = wc.getDisplayContent().getOrientation();
+ if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
+ || lastOrientation != displayAreaOrientation) {
+ updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
+ }
+ }
+ }
+
if (lastOrientation != getConfiguration().orientation) {
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
@@ -3197,9 +3234,6 @@
pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
- if (mLastFocus != mCurrentFocus) {
- pw.print(" mLastFocus="); pw.println(mLastFocus);
- }
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
if (mFixedRotationLaunchingApp != null) {
pw.println(" mFixedRotationLaunchingApp=" + mFixedRotationLaunchingApp);
@@ -3430,15 +3464,12 @@
}
}
- onWindowFocusChanged(oldFocus, newFocus);
-
- int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
+ getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayout(true /*initial*/, updateInputWindows);
- focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
@@ -3446,16 +3477,6 @@
}
}
- if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
- // The change in focus caused us to need to do a layout. Okay.
- setLayoutNeeded();
- if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
- performLayout(true /*initial*/, updateInputWindows);
- } else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) {
- mWmService.mRoot.performSurfacePlacement();
- }
- }
-
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
// If we defer assigning layers, then the caller is responsible for doing this part.
getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
@@ -3482,7 +3503,6 @@
mWmService.mAccessibilityController));
}
- mLastFocus = mCurrentFocus;
return true;
}
@@ -3490,20 +3510,6 @@
accessibilityController.onWindowFocusChangedNot(getDisplayId());
}
- private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
- final Task focusedTask = newFocus != null ? newFocus.getTask() : null;
- final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null;
- if (focusedTask == unfocusedTask) {
- return;
- }
- if (focusedTask != null) {
- focusedTask.onWindowFocusChanged(true /* hasFocus */);
- }
- if (unfocusedTask != null) {
- unfocusedTask.onWindowFocusChanged(false /* hasFocus */);
- }
- }
-
/**
* Set the new focused app to this display.
*
@@ -3527,7 +3533,14 @@
}
ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
newFocus, getDisplayId(), Debug.getCallers(4));
+ final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
+ final Task newTask = newFocus != null ? newFocus.getTask() : null;
mFocusedApp = newFocus;
+ if (oldTask != newTask) {
+ if (oldTask != null) oldTask.onAppFocusChanged(false);
+ if (newTask != null) newTask.onAppFocusChanged(true);
+ }
+
getInputMonitor().setFocusedAppLw(newFocus);
updateTouchExcludeRegion();
return true;
@@ -3991,7 +4004,9 @@
// Update Ime parent when IME insets leash created or the new IME layering target might
// updated from setImeLayeringTarget, which is the best time that default IME visibility
// has been settled down after IME control target changed.
- if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) {
+ final boolean imeParentChanged =
+ prevImeControlTarget != mImeControlTarget || forceUpdateImeParent;
+ if (imeParentChanged) {
updateImeParent();
}
@@ -3999,7 +4014,7 @@
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.post(() ->
- InputMethodManagerInternal.get().reportImeControl(token)
+ InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged)
);
}
@@ -4223,7 +4238,6 @@
if (DEBUG_INPUT_METHOD) {
Slog.i(TAG_WM, "Desired input method target: " + imFocus);
Slog.i(TAG_WM, "Current focus: " + mCurrentFocus + " displayId=" + mDisplayId);
- Slog.i(TAG_WM, "Last focus: " + mLastFocus + " displayId=" + mDisplayId);
}
if (DEBUG_INPUT_METHOD) {
@@ -4348,6 +4362,7 @@
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */);
}
+ updateMirroring();
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
if (wallpaperVisible != mLastWallpaperVisible) {
@@ -5839,7 +5854,9 @@
return false; /* continue */
}
}
-
+ if (nextWindow.isSecureLocked()) {
+ return false; /* continue */
+ }
return true; /* stop, match found */
}
});
@@ -5865,6 +5882,133 @@
return mSandboxDisplayApis;
}
+ /**
+ * Start mirroring to this DisplayContent if it does not have its own content. Captures the
+ * content of a WindowContainer indicated by a WindowToken. If unable to start mirroring, falls
+ * back to original MediaProjection approach.
+ */
+ private void startMirrorIfNeeded() {
+ // Only mirror if this display does not have its own content.
+ if (mLastHasContent) {
+ return;
+ }
+ // Given the WindowToken of the DisplayArea to mirror, retrieve the associated
+ // SurfaceControl.
+ IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
+ mDisplayId);
+
+ if (tokenToMirror == null) {
+ // This DisplayContent instance is not involved in layer mirroring. If the display
+ // has been created for capturing, fall back to prior MediaProjection approach.
+ return;
+ }
+ final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+ tokenToMirror);
+ if (wc == null) {
+ // Un-set the window token to mirror for this VirtualDisplay, to fall back to the
+ // original MediaProjection approach.
+ mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null);
+ return;
+ }
+ SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
+
+ // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
+ mMirroredSurface = SurfaceControl.mirrorSurface(sc);
+ SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
+ // Set the mMirroredSurface's parent to the root SurfaceControl for this
+ // DisplayContent. This brings the new mirrored hierarchy under this DisplayContent,
+ // so SurfaceControl will write the layers of this hierarchy to the output surface
+ // provided by the app.
+ .reparent(mMirroredSurface, mSurfaceControl)
+ // Reparent the SurfaceControl of this DisplayContent to null, to prevent content
+ // being added to it. This ensures that no app launched explicitly on the
+ // VirtualDisplay will show up as part of the mirrored content.
+ .reparent(mWindowingLayer, null);
+ // Retrieve the size of the DisplayArea to mirror.
+ updateMirroredSurface(transaction, wc.getDisplayContent().getBounds());
+ mTokenToMirror = tokenToMirror;
+
+ // No need to clean up. In SurfaceFlinger, parents hold references to their children. The
+ // mirrored SurfaceControl is alive since the parent DisplayContent SurfaceControl is
+ // holding a reference to it. Therefore, the mirrored SurfaceControl will be cleaned up
+ // when the VirtualDisplay is destroyed - which will clean up this DisplayContent.
+ }
+
+ /**
+ * Start or stop mirroring if this DisplayContent now has content, or no longer has content.
+ */
+ private void updateMirroring() {
+ if (mLastHasContent && mMirroredSurface != null) {
+ // Display now has content, so stop mirroring to it.
+ mWmService.mTransactionFactory.get()
+ // Remove the reference to mMirroredSurface, to clean up associated memory.
+ .remove(mMirroredSurface)
+ // Reparent the SurfaceControl of this DisplayContent back to mSurfaceControl,
+ // to allow content to be added to it. This allows this DisplayContent to stop
+ // mirroring and show content normally.
+ .reparent(mWindowingLayer, mSurfaceControl).apply();
+ // Stop mirroring by destroying the reference to the mirrored layer.
+ mMirroredSurface = null;
+ // Do not un-set the token, in case content is removed and mirroring should begin again.
+ } else if (!mLastHasContent && mMirroredSurface == null) {
+ // Display no longer has content, so start mirroring to it.
+ startMirrorIfNeeded();
+ }
+ }
+
+ /**
+ * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
+ * fit and centred in the output surface.
+ *
+ * @param transaction the transaction to include transformations of mMirroredSurface
+ * to. Transaction is not applied before returning.
+ * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by
+ * the app.
+ */
+ @VisibleForTesting
+ void updateMirroredSurface(SurfaceControl.Transaction transaction,
+ Rect displayAreaBounds) {
+ // Retrieve the default size of the surface the app provided to
+ // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
+ // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
+ // it writes the mirrored layers to the buffers.
+ final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
+ mDisplayId);
+
+ // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
+ // output surface.
+ float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
+ float scaleY = surfaceSize.y / (float) displayAreaBounds.height();
+ float scale = Math.min(scaleX, scaleY);
+ int scaledWidth = Math.round(scale * (float) displayAreaBounds.width());
+ int scaledHeight = Math.round(scale * (float) displayAreaBounds.height());
+
+ // Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored
+ // contents in the output surface.
+ int shiftedX = 0;
+ if (scaledWidth != surfaceSize.x) {
+ shiftedX = (surfaceSize.x - scaledWidth) / 2;
+ }
+ int shiftedY = 0;
+ if (scaledHeight != surfaceSize.y) {
+ shiftedY = (surfaceSize.y - scaledHeight) / 2;
+ }
+
+ transaction
+ // Crop the area to capture to exclude the 'extra' wallpaper that is used
+ // for parallax (b/189930234).
+ .setWindowCrop(mMirroredSurface, displayAreaBounds.width(),
+ displayAreaBounds.height())
+ // Scale the root mirror SurfaceControl, based upon the size difference between the
+ // source (DisplayArea to capture) and output (surface the app reads images from).
+ .setMatrix(mMirroredSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
+ // Position needs to be updated when the mirrored DisplayArea has changed, since
+ // the content will no longer be centered in the output surface.
+ .setPosition(mMirroredSurface, shiftedX /* x */, shiftedY /* y */)
+ .apply();
+ mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds);
+ }
+
/** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
@@ -6009,7 +6153,7 @@
class RemoteInsetsControlTarget implements InsetsControlTarget {
private final IDisplayWindowInsetsController mRemoteInsetsController;
- private final InsetsState mRequestedInsetsState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
mRemoteInsetsController = controller;
@@ -6071,15 +6215,11 @@
if (type == ITYPE_IME) {
return getInsetsStateController().getImeSourceProvider().isImeShowing();
}
- return mRequestedInsetsState.getSourceOrDefaultVisibility(type);
+ return mRequestedVisibilities.getVisibility(type);
}
- void updateRequestedVisibility(InsetsState state) {
- for (int i = 0; i < InsetsState.SIZE; i++) {
- final InsetsSource source = state.peekSource(i);
- if (source == null) continue;
- mRequestedInsetsState.addSource(source);
- }
+ void setRequestedVisibilities(InsetsVisibilities requestedVisibilities) {
+ mRequestedVisibilities.set(requestedVisibilities);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f19a2c1..801182c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -140,6 +140,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.View;
import android.view.ViewDebug;
@@ -339,7 +340,7 @@
private int mLastDisableFlags;
private int mLastAppearance;
private int mLastBehavior;
- private final InsetsState mRequestedState = new InsetsState();
+ private InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
private AppearanceRegion[] mLastStatusBarAppearanceRegions;
/** The union of checked bounds while fetching {@link #mStatusBarColorWindows}. */
@@ -1983,11 +1984,7 @@
mTopIsFullscreen = topIsFullscreen;
}
- if (updateSystemUiVisibilityLw()) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
+ updateSystemBarAttributes();
if (mShowingDream != mLastShowingDream) {
mLastShowingDream = mShowingDream;
@@ -2290,7 +2287,8 @@
return width;
}
- private int getNavigationBarHeight(int rotation, int uiMode) {
+ @VisibleForTesting
+ int getNavigationBarHeight(int rotation, int uiMode) {
if (INSETS_LAYOUT_GENERALIZATION) {
if (mNavigationBar == null) {
return 0;
@@ -2526,18 +2524,13 @@
/**
* A new window has been focused.
*/
- public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
+ public void focusChangedLw(WindowState lastFocus, WindowState newFocus) {
mFocusedWindow = newFocus;
mLastFocusedWindow = lastFocus;
if (mDisplayContent.isDefaultDisplay) {
mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
}
- if (updateSystemUiVisibilityLw()) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- return FINISH_LAYOUT_REDO_LAYOUT;
- }
- return 0;
+ updateSystemBarAttributes();
}
private void requestTransientBars(WindowState swipeTarget) {
@@ -2613,21 +2606,18 @@
return mDisplayContent.getInsetsPolicy();
}
- void resetSystemUiVisibilityLw() {
+ void resetSystemBarAttributes() {
mLastDisableFlags = 0;
- updateSystemUiVisibilityLw();
+ updateSystemBarAttributes();
}
- /**
- * @return {@code true} if the update may affect the layout.
- */
- boolean updateSystemUiVisibilityLw() {
+ void updateSystemBarAttributes() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return false;
+ return;
}
// The immersive mode confirmation should never affect the system bar visibility, otherwise
@@ -2643,12 +2633,13 @@
: lastFocusCanReceiveKeys ? mLastFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return false;
+ return;
}
}
final WindowState win = winCandidate;
mSystemUiControllingWindow = win;
+ final int displayId = getDisplayId();
final int disableFlags = win.getDisableFlags();
final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
final WindowState navColorWin = chooseNavigationColorWindowLw(mNavBarColorWindowCandidate,
@@ -2658,9 +2649,9 @@
final int appearance = updateLightNavigationBarLw(win.mAttrs.insetsFlags.appearance,
navColorWin) | opaqueAppearance;
final int behavior = win.mAttrs.insetsFlags.behavior;
+ final String focusedApp = win.mAttrs.packageName;
final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR)
|| !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
-
final AppearanceRegion[] appearanceRegions =
new AppearanceRegion[mStatusBarColorWindows.size()];
for (int i = mStatusBarColorWindows.size() - 1; i >= 0; i--) {
@@ -2669,40 +2660,36 @@
getStatusBarAppearance(windowState, windowState),
new Rect(windowState.getFrame()));
}
-
- if (mLastDisableFlags == disableFlags
- && mLastAppearance == appearance
+ if (mLastDisableFlags != disableFlags) {
+ mLastDisableFlags = disableFlags;
+ final String cause = win.toString();
+ callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags,
+ cause));
+ }
+ if (mLastAppearance == appearance
&& mLastBehavior == behavior
- && mRequestedState.equals(win.getRequestedState())
- && Objects.equals(mFocusedApp, win.mAttrs.packageName)
+ && mRequestedVisibilities.equals(win.getRequestedVisibilities())
+ && Objects.equals(mFocusedApp, focusedApp)
&& mLastFocusIsFullscreen == isFullscreen
&& Arrays.equals(mLastStatusBarAppearanceRegions, appearanceRegions)) {
- return false;
+ return;
}
if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
&& ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
mService.mInputManager.setSystemUiLightsOut(
isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
}
- mLastDisableFlags = disableFlags;
+ final InsetsVisibilities requestedVisibilities =
+ new InsetsVisibilities(win.getRequestedVisibilities());
mLastAppearance = appearance;
mLastBehavior = behavior;
- mRequestedState.set(win.getRequestedState(), true /* copySources */);
- mFocusedApp = win.mAttrs.packageName;
+ mRequestedVisibilities = requestedVisibilities;
+ mFocusedApp = focusedApp;
mLastFocusIsFullscreen = isFullscreen;
mLastStatusBarAppearanceRegions = appearanceRegions;
- final String cause = win.toString();
- mHandler.post(() -> {
- StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
- if (statusBar != null) {
- final int displayId = getDisplayId();
- statusBar.setDisableFlags(displayId, disableFlags, cause);
- statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- isNavbarColorManagedByIme, behavior, mRequestedState, mFocusedApp);
-
- }
- });
- return true;
+ callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId,
+ appearance, appearanceRegions, isNavbarColorManagedByIme, behavior,
+ requestedVisibilities, focusedApp));
}
private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) {
@@ -2713,6 +2700,15 @@
: 0;
}
+ private void callStatusBarSafely(Consumer<StatusBarManagerInternal> consumer) {
+ mHandler.post(() -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ consumer.accept(statusBar);
+ }
+ });
+ }
+
@VisibleForTesting
@Nullable
static WindowState chooseNavigationColorWindowLw(WindowState candidate, WindowState imeWindow,
@@ -2965,7 +2961,7 @@
return;
}
mPendingPanicGestureUptime = SystemClock.uptimeMillis();
- updateSystemUiVisibilityLw();
+ updateSystemBarAttributes();
}
}
};
@@ -3152,7 +3148,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/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index d12d07a..d073f94 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -291,12 +291,14 @@
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder());
}
+ mCallback.get().dragRecipientEntered(window);
}
void dragRecipientExited(IWindow window) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder());
}
+ mCallback.get().dragRecipientExited(window);
}
/**
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index 53b6b41..eab3f10 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -66,10 +66,8 @@
} else {
mNavBarToken = null;
}
- // Do not fade notification shade when running fixed rotation (not frozen) because it may
- // need to animate with the launching app.
- final WindowState notificationShade = mFrozenTimeoutRunnable == null
- ? displayPolicy.getNotificationShade() : null;
+ // Collect the target windows to fade out. The display won't wait for them to unfreeze.
+ final WindowState notificationShade = displayPolicy.getNotificationShade();
displayContent.forAllWindows(w -> {
if (w.mActivityRecord == null && w.mHasSurface && !w.mForceSeamlesslyRotate
&& !w.mIsWallpaper && !w.mIsImWindow && w != navigationBar
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index d9112c5..895a82b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -138,12 +138,19 @@
abortTransient();
}
mFocusedWin = focusedWin;
- InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin);
- InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin);
- mStateController.onBarControlTargetChanged(statusControlTarget,
- getFakeControlTarget(focusedWin, statusControlTarget),
+ final InsetsControlTarget statusControlTarget =
+ getStatusControlTarget(focusedWin, false /* fake */);
+ final InsetsControlTarget navControlTarget =
+ getNavControlTarget(focusedWin, false /* fake */);
+ mStateController.onBarControlTargetChanged(
+ statusControlTarget,
+ statusControlTarget == mDummyControlTarget
+ ? getStatusControlTarget(focusedWin, true /* fake */)
+ : null,
navControlTarget,
- getFakeControlTarget(focusedWin, navControlTarget));
+ navControlTarget == mDummyControlTarget
+ ? getNavControlTarget(focusedWin, true /* fake */)
+ : null);
mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
}
@@ -330,13 +337,9 @@
mShowingTransientTypes.clear();
}
- private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused,
- InsetsControlTarget realControlTarget) {
- return realControlTarget == mDummyControlTarget ? focused : null;
- }
-
- private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
- if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
+ private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
+ boolean fake) {
+ if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1 && !fake) {
return mDummyControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -354,7 +357,7 @@
// we will dispatch the real visibility of status bar to the client.
return null;
}
- if (forceShowsStatusBarTransiently()) {
+ if (forceShowsStatusBarTransiently() && !fake) {
// Status bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -379,13 +382,14 @@
&& !win.inMultiWindowMode();
}
- private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
+ private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
+ boolean fake) {
final WindowState imeWin = mDisplayContent.mInputMethodWindow;
if (imeWin != null && imeWin.isVisible()) {
// Force showing navigation bar while IME is visible.
return null;
}
- if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
+ if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1 && !fake) {
return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
@@ -402,7 +406,7 @@
// bar, and we will dispatch the real visibility of navigation bar to the client.
return null;
}
- if (forceShowsNavigationBarTransiently()) {
+ if (forceShowsNavigationBarTransiently() && !fake) {
// Navigation bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index cbd1314..f3e52f2 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -376,8 +376,11 @@
return;
}
mClientVisible = clientVisible;
- mDisplayContent.mWmService.mH.obtainMessage(
- LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+ if (!mDisplayContent.mLayoutAndAssignWindowLayersScheduled) {
+ mDisplayContent.mLayoutAndAssignWindowLayersScheduled = true;
+ mDisplayContent.mWmService.mH.obtainMessage(
+ LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+ }
updateVisibility();
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 655007c..2c4adcb 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -385,7 +385,7 @@
if (changed) {
notifyInsetsChanged();
mDisplayContent.updateSystemGestureExclusion();
- mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
+ mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 672ebf1..9cd8c2d 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -49,6 +49,7 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.WindowManager;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -158,6 +159,7 @@
final boolean keyguardChanged = (keyguardShowing != mKeyguardShowing)
|| (mKeyguardGoingAway && keyguardShowing && !aodChanged);
if (!keyguardChanged && !aodChanged) {
+ setWakeTransitionReady();
return;
}
EventLogTags.writeWmSetKeyguardShown(
@@ -203,6 +205,15 @@
updateKeyguardSleepToken();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+ setWakeTransitionReady();
+ }
+
+ private void setWakeTransitionReady() {
+ if (mWindowManager.mAtmService.getTransitionController().getCollectingTransitionType()
+ == WindowManager.TRANSIT_WAKE) {
+ mWindowManager.mAtmService.getTransitionController().setReady(
+ mRootWindowContainer.getDefaultDisplay());
+ }
}
/**
@@ -334,6 +345,7 @@
for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
+ if (display.isRemoving() || display.isRemoved()) continue;
final KeyguardDisplayState state = getDisplayState(display.mDisplayId);
state.updateVisibility(this, display);
requestDismissKeyguard |= state.mRequestDismissKeyguard;
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index d230936..88941eb 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -138,7 +138,7 @@
mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
- mWindowContainer.getWindowConfiguration(), true, null, null, null,
+ mWindowContainer.getWindowConfiguration(), true, null, null, null, false,
mWindowContainer.getWindowType());
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 7e95e7d..4f7c9a4 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -211,7 +211,9 @@
}
mFreezingTaskConfig = true;
mDestRotatedBounds = new Rect(bounds);
- continueOrientationChange();
+ if (!mService.mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+ continueOrientationChange();
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 455f568..ede4c2e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1108,13 +1108,15 @@
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
- removeForAddTask(task);
+ final int removedIndex = removeForAddTask(task);
task.inRecents = true;
if (!isAffiliated || needAffiliationFix) {
// If this is a simple non-affiliated task, or we had some failure trying to
// handle it as part of an affilated task, then just place it at the top.
- mTasks.add(0, task);
+ // But if the list is frozen, adding the task to the removed index to keep the order.
+ int indexToAdd = mFreezeTaskListReordering && removedIndex != -1 ? removedIndex : 0;
+ mTasks.add(indexToAdd, task);
notifyTaskAdded(task);
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
} else if (isAffiliated) {
@@ -1482,14 +1484,14 @@
* If needed, remove oldest existing entries in recents that are for the same kind
* of task as the given one.
*/
- private void removeForAddTask(Task task) {
+ private int removeForAddTask(Task task) {
// The adding task will be in recents so it is not hidden.
mHiddenTasks.remove(task);
final int removeIndex = findRemoveIndexForAddTask(task);
if (removeIndex == -1) {
// Nothing to trim
- return;
+ return removeIndex;
}
// There is a similar task that will be removed for the addition of {@param task}, but it
@@ -1511,6 +1513,7 @@
}
}
notifyTaskPersisterLocked(removedTask, false /* flush */);
+ return removeIndex;
}
/**
@@ -1518,11 +1521,6 @@
* list (if any).
*/
private int findRemoveIndexForAddTask(Task task) {
- if (mFreezeTaskListReordering) {
- // Defer removing tasks due to the addition of new tasks until the task list is unfrozen
- return -1;
- }
-
final int recentsCount = mTasks.size();
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
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/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e346e3e..4f93c7a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1201,7 +1201,8 @@
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
- mIsRecentTaskInvisible, null, null, mTask.getTaskInfo());
+ mIsRecentTaskInvisible, null, null, mTask.getTaskInfo(),
+ topApp.checkEnterPictureInPictureAppOpsState());
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 7cd3e70..24c5c82 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;
}
@@ -2158,7 +2157,7 @@
rootTask.setLastRecentsAnimationTransaction(
task.mLastRecentsAnimationTransaction,
task.mLastRecentsAnimationOverlay);
- task.clearLastRecentsAnimationTransaction();
+ task.clearLastRecentsAnimationTransaction(false /* forceRemoveOverlay */);
}
// There are multiple activities in the task and moving the top activity should
@@ -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() {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index e282012..0b56777 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -69,6 +69,7 @@
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -113,7 +114,7 @@
private float mLastReportedAnimatorScale;
private String mPackageName;
private String mRelayoutTag;
- private final InsetsState mDummyRequestedVisibility = new InsetsState();
+ private final InsetsVisibilities mDummyRequestedVisibilities = new InsetsVisibilities();
private final InsetsSourceControl[] mDummyControls = new InsetsSourceControl[0];
public Session(WindowManagerService service, IWindowSessionCallback callback) {
@@ -187,29 +188,28 @@
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
- UserHandle.getUserId(mUid), requestedVisibility, outInputChannel, outInsetsState,
+ UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState,
outActiveControls);
}
-
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
+ int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
- requestedVisibility, outInputChannel, outInsetsState, outActiveControls);
+ requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
@Override
public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsState outInsetsState) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
- UserHandle.getUserId(mUid), mDummyRequestedVisibility, null /* outInputChannel */,
+ UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */,
outInsetsState, mDummyControls);
}
@@ -624,12 +624,12 @@
}
@Override
- public void insetsModified(IWindow window, InsetsState state) {
+ public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) {
synchronized (mService.mGlobalLock) {
final WindowState windowState = mService.windowForClientLocked(this, window,
false /* throwOnError */);
if (windowState != null) {
- windowState.updateRequestedVisibility(state);
+ windowState.setRequestedVisibilities(visibilities);
windowState.getDisplayContent().getInsetsPolicy().onInsetsModified(windowState);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 709052e..5996083 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -180,7 +180,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -1203,7 +1202,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);
}
}
@@ -3031,18 +3030,6 @@
return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS);
}
- @Override
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- final ActivityRecord activity = getTopMostActivity();
- return activity != null ? activity.createRemoteAnimationTarget(record) : null;
- }
-
- @Override
- boolean canCreateRemoteAnimationTarget() {
- return true;
- }
-
WindowState getTopVisibleAppMainWindow() {
final ActivityRecord activity = getTopVisibleActivity();
return activity != null ? activity.findMainWindow() : null;
@@ -3527,7 +3514,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);
@@ -3691,6 +3680,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=");
@@ -4325,10 +4316,10 @@
* @return true if the task is currently focused.
*/
private boolean isFocused() {
- if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
+ if (mDisplayContent == null || mDisplayContent.mFocusedApp == null) {
return false;
}
- return mDisplayContent.mCurrentFocus.getTask() == this;
+ return mDisplayContent.mFocusedApp.getTask() == this;
}
/**
@@ -4385,10 +4376,9 @@
* Called on the task of a window which gained or lost focus.
* @param hasFocus
*/
- void onWindowFocusChanged(boolean hasFocus) {
+ void onAppFocusChanged(boolean hasFocus) {
updateShadowsRadius(hasFocus, getSyncTransaction());
- // TODO(b/180525887): Un-comment once there is resolution on the bug.
- // dispatchTaskInfoChangedIfNeeded(false /* force */);
+ dispatchTaskInfoChangedIfNeeded(false /* force */);
}
void onPictureInPictureParamsChanged() {
@@ -4574,7 +4564,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
@@ -4632,7 +4622,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();
}
@@ -4640,10 +4631,8 @@
mAtmService.continueWindowLayout();
}
- if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedTasksTopActivities();
- }
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
void resumeNextFocusAfterReparent() {
@@ -5069,7 +5058,7 @@
}
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
- boolean newTask, boolean keepCurTransition, ActivityOptions options,
+ boolean newTask, boolean isTaskSwitch, ActivityOptions options,
@Nullable ActivityRecord sourceRecord) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
@@ -5190,7 +5179,7 @@
}
}
- r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity),
+ r.showStartingWindow(prev, newTask, isTaskSwitch,
true /* startActivity */, sourceRecord);
}
} else {
@@ -5224,10 +5213,6 @@
return true;
}
- private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) {
- return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
- }
-
/**
* Reset the task by reparenting the activities that have same affinity to the task or
* reparenting the activities that have different affinityies out of the task, while these
@@ -6042,7 +6027,10 @@
mLastRecentsAnimationOverlay = overlay;
}
- void clearLastRecentsAnimationTransaction() {
+ void clearLastRecentsAnimationTransaction(boolean forceRemoveOverlay) {
+ if (forceRemoveOverlay && mLastRecentsAnimationOverlay != null) {
+ getPendingTransaction().remove(mLastRecentsAnimationOverlay);
+ }
mLastRecentsAnimationTransaction = null;
mLastRecentsAnimationOverlay = null;
// reset also the crop and transform introduced by mLastRecentsAnimationTransaction
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 10c16ff..6c8cde43 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -780,10 +780,12 @@
}
return SCREEN_ORIENTATION_UNSPECIFIED;
} else {
- // Apps and their containers are not allowed to specify an orientation of full screen
- // tasks created by organizer. The organizer handles the orientation instead.
- final Task task = getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- if (task != null && task.isVisible() && task.mCreatedByOrganizer) {
+ // Apps and their containers are not allowed to specify an orientation of non floating
+ // visible tasks created by organizer. The organizer handles the orientation instead.
+ final Task nonFloatingTopTask =
+ getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
+ if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
+ && nonFloatingTopTask.isVisible()) {
return SCREEN_ORIENTATION_UNSPECIFIED;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 9159bbb..999df30 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -83,9 +83,11 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOrganizerToken;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -159,7 +161,8 @@
/** Avoid reentrant of {@link #removeImmediately()}. */
private boolean mRemoving;
- // The TaskFragment that adjacent to this one.
+ /** The TaskFragment that is adjacent to this one. */
+ @Nullable
private TaskFragment mAdjacentTaskFragment;
/**
@@ -280,13 +283,27 @@
mRemoteToken = new RemoteToken(this);
}
- void setAdjacentTaskFragment(TaskFragment taskFragment) {
- mAdjacentTaskFragment = taskFragment;
- taskFragment.mAdjacentTaskFragment = this;
+ void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
+ if (mAdjacentTaskFragment == taskFragment) {
+ return;
+ }
+ resetAdjacentTaskFragment();
+ if (taskFragment != null) {
+ mAdjacentTaskFragment = taskFragment;
+ taskFragment.setAdjacentTaskFragment(this);
+ }
}
- void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer, int pid) {
- mTaskFragmentOrganizer = organizer;
+ private void resetAdjacentTaskFragment() {
+ // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
+ if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
+ mAdjacentTaskFragment.mAdjacentTaskFragment = null;
+ }
+ mAdjacentTaskFragment = null;
+ }
+
+ void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
+ mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
mTaskFragmentOrganizerPid = pid;
}
@@ -1486,6 +1503,18 @@
// No app transition applied to the task fragment.
}
+ @Override
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ final ActivityRecord activity = getTopMostActivity();
+ return activity != null ? activity.createRemoteAnimationTarget(record) : null;
+ }
+
+ @Override
+ boolean canCreateRemoteAnimationTarget() {
+ return true;
+ }
+
boolean shouldSleepActivities() {
return false;
}
@@ -1895,6 +1924,7 @@
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
+ hasRunningActivity(this),
isVisible(),
childActivities,
positionInParent);
@@ -1936,6 +1966,7 @@
return;
}
mRemoving = true;
+ resetAdjacentTaskFragment();
super.removeImmediately();
sendTaskFragmentVanished();
mRemoving = false;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 496ecde..a322384 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;
@@ -113,8 +116,11 @@
}
void dispose() {
- mOrganizedTaskFragments.forEach(TaskFragment::removeImmediately);
- mOrganizedTaskFragments.clear();
+ while (!mOrganizedTaskFragments.isEmpty()) {
+ final TaskFragment taskFragment = mOrganizedTaskFragments.get(0);
+ taskFragment.removeImmediately();
+ mOrganizedTaskFragments.remove(taskFragment);
+ }
mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
}
@@ -190,6 +196,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 +305,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 +345,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 +451,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/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index c85615d..54390dc 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -114,14 +114,9 @@
private final boolean mIsRunningOnIoT;
/**
- * Flag indicating whether we are running on an Android Wear device.
+ * Flag indicating if task snapshot is enabled on this device.
*/
- private final boolean mIsRunningOnWear;
-
- /**
- * Flag indicating if device configuration has disabled app snapshots.
- */
- private final boolean mConfigDisableTaskSnapshots;
+ private boolean mTaskSnapshotEnabled;
TaskSnapshotController(WindowManagerService service) {
mService = service;
@@ -132,12 +127,12 @@
PackageManager.FEATURE_LEANBACK);
mIsRunningOnIoT = mService.mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_EMBEDDED);
- mIsRunningOnWear = mService.mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WATCH);
mHighResTaskSnapshotScale = mService.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_highResTaskSnapshotScale);
- mConfigDisableTaskSnapshots = mService.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_disableTaskSnapshots);
+ mTaskSnapshotEnabled =
+ !mService.mContext
+ .getResources()
+ .getBoolean(com.android.internal.R.bool.config_disableTaskSnapshots);
}
void systemReady() {
@@ -494,9 +489,12 @@
return builder.build();
}
+ void setTaskSnapshotEnabled(boolean enabled) {
+ mTaskSnapshotEnabled = enabled;
+ }
+
boolean shouldDisableSnapshots() {
- return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT
- || mConfigDisableTaskSnapshots;
+ return mIsRunningOnTv || mIsRunningOnIoT || !mTaskSnapshotEnabled;
}
/**
@@ -696,6 +694,7 @@
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mHighResTaskSnapshotScale=" + mHighResTaskSnapshotScale);
+ pw.println(prefix + "mTaskSnapshotEnabled=" + mTaskSnapshotEnabled);
mCache.dump(pw, prefix);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index cc4abab..059eb87 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -72,6 +72,7 @@
import android.view.IWindowSession;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -166,6 +167,7 @@
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
final Rect taskBounds;
final InsetsState mTmpInsetsState = new InsetsState();
+ final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
final TaskDescription taskDescription = new TaskDescription();
@@ -227,7 +229,8 @@
int displayId = activity.getDisplayContent().getDisplayId();
try {
final int res = session.addToDisplay(window, layoutParams, View.GONE, displayId,
- mTmpInsetsState, null /* outInputChannel */, mTmpInsetsState, mTempControls);
+ mRequestedVisibilities, null /* outInputChannel */, mTmpInsetsState,
+ mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 1ac1666..6bfa611 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -33,10 +33,13 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -46,18 +49,19 @@
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;
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.animation.Animation;
import android.window.IRemoteTransition;
import android.window.TransitionInfo;
@@ -65,6 +69,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;
@@ -106,9 +111,9 @@
@Retention(RetentionPolicy.SOURCE)
@interface TransitionState {}
- final @WindowManager.TransitionType int mType;
+ final @TransitionType int mType;
private int mSyncId;
- private @WindowManager.TransitionFlags int mFlags;
+ private @TransitionFlags int mFlags;
private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
private IRemoteTransition mRemoteTransition = null;
@@ -130,7 +135,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();
@@ -140,7 +148,7 @@
private boolean mNavBarAttachedToApp = false;
private int mNavBarDisplayId = INVALID_DISPLAY;
- Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags,
+ Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
mType = type;
mFlags = flags;
@@ -226,13 +234,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 +373,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 +384,8 @@
.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
}
+ sendRemoteCallback(mClientAnimationFinishCallback);
+
legacyRestoreNavigationBarFromApp();
}
@@ -426,6 +449,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 +463,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;
@@ -574,7 +619,7 @@
}
private void handleNonAppWindowsInTransition(int displayId,
- @WindowManager.TransitionType int transit, int flags) {
+ @TransitionType int transit, int flags) {
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
if (dc == null) {
@@ -661,6 +706,22 @@
return wc.asWallpaperToken() != null;
}
+ private static boolean occludesKeyguard(WindowContainer wc) {
+ final ActivityRecord ar = wc.asActivityRecord();
+ if (ar != null) {
+ return ar.canShowWhenLocked();
+ }
+ final Task t = wc.asTask();
+ if (t != null) {
+ // Get the top activity which was visible (since this is going away, it will remain
+ // client visible until the transition is finished).
+ // skip hidden (or about to hide) apps
+ final ActivityRecord top = t.getActivity(WindowToken::isClientVisible);
+ return top != null && top.canShowWhenLocked();
+ }
+ return false;
+ }
+
/**
* Under some conditions (eg. all visible targets within a parent container are transitioning
* the same way) the transition can be "promoted" to the parent container. This means an
@@ -808,7 +869,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);
@@ -921,7 +986,7 @@
*/
@VisibleForTesting
@NonNull
- static TransitionInfo calculateTransitionInfo(int type, int flags,
+ static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
ArraySet<WindowContainer> targets, ArrayMap<WindowContainer, ChangeInfo> changes) {
final TransitionInfo out = new TransitionInfo(type, flags);
@@ -1105,6 +1170,9 @@
if (isWallpaper(wc)) {
flags |= FLAG_IS_WALLPAPER;
}
+ if (occludesKeyguard(wc)) {
+ flags |= FLAG_OCCLUDES_KEYGUARD;
+ }
return flags;
}
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/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 416b9df..25f7269 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -93,7 +93,7 @@
RemoteAnimationTarget createRemoteAnimationTarget() {
mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
- mWallpaperToken.getWindowConfiguration(), true, null, null, null);
+ mWallpaperToken.getWindowConfiguration(), true, null, null, null, false);
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 95e5fc2..0f61f1a 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
@@ -79,6 +81,8 @@
private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
private final float mMaxWallpaperScale;
+ // Whether COMMAND_FREEZE was dispatched.
+ private boolean mLastFrozen = false;
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
@@ -194,6 +198,7 @@
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Win " + w + ": token animating, looking behind.");
}
+ mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground());
// Found a target! End search.
return true;
}
@@ -424,20 +429,25 @@
Bundle sendWindowWallpaperCommand(
WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
- boolean doWait = sync;
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
- token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
- }
-
- if (doWait) {
- // TODO: Need to wait for result.
- }
+ sendWindowWallpaperCommand(action, x, y, z, extras, sync);
}
return null;
}
+ private void sendWindowWallpaperCommand(
+ String action, int x, int y, int z, Bundle extras, boolean sync) {
+ boolean doWait = sync;
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
+ token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
+ }
+
+ if (doWait) {
+ // TODO: Need to wait for result.
+ }
+ }
+
private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
WindowState target = mWallpaperTarget;
if (target != null) {
@@ -641,6 +651,13 @@
updateWallpaperTokens(visible);
+ if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) {
+ mLastFrozen = mFindResults.isWallpaperTargetForLetterbox;
+ sendWindowWallpaperCommand(
+ mFindResults.isWallpaperTargetForLetterbox ? COMMAND_FREEZE : COMMAND_UNFREEZE,
+ /* x= */ 0, /* y= */ 0, /* z= */ 0, /* extras= */ null, /* sync= */ false);
+ }
+
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
+ " prev=" + mPrevWallpaperTarget);
}
@@ -838,6 +855,7 @@
boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
boolean resetTopWallpaper = false;
+ boolean isWallpaperTargetForLetterbox = false;
void setTopWallpaper(WindowState win) {
topWallpaper = win;
@@ -851,11 +869,16 @@
useTopWallpaperAsTarget = topWallpaperAsTarget;
}
+ void setIsWallpaperTargetForLetterbox(boolean isWallpaperTargetForLetterbox) {
+ this.isWallpaperTargetForLetterbox = isWallpaperTargetForLetterbox;
+ }
+
void reset() {
topWallpaper = null;
wallpaperTarget = null;
useTopWallpaperAsTarget = false;
resetTopWallpaper = false;
+ isWallpaperTargetForLetterbox = false;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 5bc4d49..6a6d3c9 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);
}
/**
@@ -298,6 +288,16 @@
* Called when drag operation was cancelled.
*/
default void postCancelDragAndDrop() {}
+
+ /**
+ * Called when it has entered a View that is willing to accept the drop.
+ */
+ default void dragRecipientEntered(IWindow window) {}
+
+ /**
+ * Called when it has exited a View that is willing to accept the drop.
+ */
+ default void dragRecipientExited(IWindow window) {}
}
/**
@@ -375,9 +375,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..d357e22 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -249,6 +249,7 @@
import android.view.InputWindowHandle;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
@@ -451,14 +452,14 @@
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
- public static final boolean sEnableRemoteKeyguardGoingAwayAnimation = !sEnableShellTransitions
- && sEnableRemoteKeyguardAnimation >= 1;
+ public static final boolean sEnableRemoteKeyguardGoingAwayAnimation =
+ sEnableRemoteKeyguardAnimation >= 1;
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
- public static final boolean sEnableRemoteKeyguardOccludeAnimation = !sEnableShellTransitions
- && sEnableRemoteKeyguardAnimation >= 2;
+ public static final boolean sEnableRemoteKeyguardOccludeAnimation =
+ sEnableRemoteKeyguardAnimation >= 2;
/**
* Allows a fullscreen windowing mode activity to launch in its desired orientation directly
@@ -1456,7 +1457,7 @@
}
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
- int displayId, int requestUserId, InsetsState requestedVisibility,
+ int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
Arrays.fill(outActiveControls, null);
@@ -1678,7 +1679,7 @@
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
- win.updateRequestedVisibility(requestedVisibility);
+ win.setRequestedVisibilities(requestedVisibilities);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != ADD_OKAY) {
@@ -3049,7 +3050,7 @@
mSettingsObserver.updateSystemUiSettings(true /* handleChange */);
synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
- mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
+ mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemBarAttributes);
}
}
@@ -4158,7 +4159,7 @@
}
@Override
- public void modifyDisplayWindowInsets(int displayId, InsetsState state) {
+ public void updateDisplayWindowRequestedVisibilities(int displayId, InsetsVisibilities vis) {
if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
@@ -4170,7 +4171,7 @@
if (dc == null || dc.mRemoteInsetsControlTarget == null) {
return;
}
- dc.mRemoteInsetsControlTarget.updateRequestedVisibility(state);
+ dc.mRemoteInsetsControlTarget.setRequestedVisibilities(vis);
dc.getInsetsStateController().onInsetsModified(dc.mRemoteInsetsControlTarget);
}
} finally {
@@ -5291,6 +5292,7 @@
case LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED: {
synchronized (mGlobalLock) {
final DisplayContent displayContent = (DisplayContent) msg.obj;
+ displayContent.mLayoutAndAssignWindowLayersScheduled = false;
displayContent.layoutAndAssignWindowLayersIfNeeded();
}
break;
@@ -7455,20 +7457,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;
}
}
@@ -8669,4 +8669,9 @@
: DEFAULT_DISPLAY;
}
}
+
+ @Override
+ public void setTaskSnapshotEnabled(boolean enabled) {
+ mTaskSnapshotController.setTaskSnapshotEnabled(enabled);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 45b5875..e62a6e4 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;
@@ -28,6 +29,7 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
@@ -44,6 +46,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 +322,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 +372,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 +411,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 +432,6 @@
mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
}
} finally {
- mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
mService.continueWindowLayout();
}
}
@@ -528,7 +529,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 +657,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 +670,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 +714,22 @@
+ oldParent);
break;
}
- reparentTaskFragment(oldParent, newParent);
+ reparentTaskFragment(oldParent, newParent, errorCallbackToken);
+ break;
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
+ fragmentToken = hop.getContainer();
+ final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
+ final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
+ final TaskFragment tf2 = adjacentFragmentToken != null
+ ? mLaunchTaskFragments.get(adjacentFragmentToken)
+ : null;
+ if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to set adjacent on invalid fragment tokens");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
+ }
+ tf1.setAdjacentTaskFragment(tf2);
break;
}
return effects;
@@ -1037,9 +1063,11 @@
// valid.
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
// We are allowing organizer to start/reparent activity to a TaskFragment it
- // created. Nothing to check here because the TaskFragment may not be created
- // yet, but will be created in the same transaction.
+ // created, or set two TaskFragments adjacent to each other. Nothing to check
+ // here because the TaskFragment may not be created yet, but will be created in
+ // the same transaction.
break;
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
enforceTaskFragmentOrganized(func,
@@ -1079,37 +1107,51 @@
}
}
- void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
+ void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
+ @Nullable IBinder errorCallbackToken) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
+ final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
+ creationParams.getOrganizer().asBinder());
+
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(organizer, 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(organizer, 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 +1159,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 +1183,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/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4b21fa5..1a34768 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -239,6 +239,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
import android.view.Surface;
import android.view.Surface.Rotation;
import android.view.SurfaceControl;
@@ -749,7 +750,7 @@
private boolean mIsDimming = false;
private @Nullable InsetsSourceProvider mControllableInsetProvider;
- private final InsetsState mRequestedInsetsState = new InsetsState();
+ private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
/**
* Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
@@ -872,27 +873,23 @@
*/
@Override
public boolean getRequestedVisibility(@InternalInsetsType int type) {
- return mRequestedInsetsState.getSourceOrDefaultVisibility(type);
+ return mRequestedVisibilities.getVisibility(type);
}
/**
* Returns all the requested visibilities.
*
- * @return an {@link InsetsState} as the requested visibilities.
+ * @return an {@link InsetsVisibilities} as the requested visibilities.
*/
- InsetsState getRequestedState() {
- return mRequestedInsetsState;
+ InsetsVisibilities getRequestedVisibilities() {
+ return mRequestedVisibilities;
}
/**
* @see #getRequestedVisibility(int)
*/
- void updateRequestedVisibility(InsetsState state) {
- for (int i = 0; i < InsetsState.SIZE; i++) {
- final InsetsSource source = state.peekSource(i);
- if (source == null) continue;
- mRequestedInsetsState.addSource(source);
- }
+ void setRequestedVisibilities(InsetsVisibilities visibilities) {
+ mRequestedVisibilities.set(visibilities);
}
/**
@@ -1173,7 +1170,8 @@
if (WindowManager.LayoutParams.isSystemAlertWindowType(mAttrs.type)) {
return TouchOcclusionMode.USE_OPACITY;
}
- if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)) {
+ if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)
+ || mWmService.mAtmService.getTransitionController().inTransition(this)) {
return TouchOcclusionMode.USE_OPACITY;
}
return TouchOcclusionMode.BLOCK_UNTRUSTED;
@@ -1444,6 +1442,14 @@
}
}
+ @Override
+ public Rect getBounds() {
+ // The window bounds are used for layout in screen coordinates. If the token has bounds for
+ // size compatibility mode, its configuration bounds are app based coordinates which should
+ // not be used for layout.
+ return mToken.hasSizeCompatBounds() ? mToken.getBounds() : super.getBounds();
+ }
+
/** Retrieves the current frame of the window that the application sees. */
Rect getFrame() {
return mWindowFrames.mFrame;
@@ -4405,9 +4411,9 @@
pw.println(prefix + "mEmbeddedDisplayContents=" + mEmbeddedDisplayContents);
}
if (dumpAll) {
- final String visibilityString = mRequestedInsetsState.toSourceVisibilityString();
+ final String visibilityString = mRequestedVisibilities.toString();
if (!visibilityString.isEmpty()) {
- pw.println(prefix + "Requested visibility: " + visibilityString);
+ pw.println(prefix + "Requested visibilities: " + visibilityString);
}
}
}
@@ -6047,8 +6053,11 @@
}
boolean hasWallpaper() {
- return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
- || (mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox());
+ return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0 || hasWallpaperForLetterboxBackground();
+ }
+
+ boolean hasWallpaperForLetterboxBackground() {
+ return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
}
/**
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 787f588..3f3d0bd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1585,6 +1585,9 @@
// all listeners have the chance to react with special handling.
Settings.Global.putInt(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 1);
+ } else if (context.getResources().getBoolean(R.bool.config_autoResetAirplaneMode)) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0);
}
StatusBarManagerService statusBar = null;
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/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/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 17a5dcc..3cab5ec 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.MANAGE_APPOPS"/>
<uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
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/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 0efcc57..34856e2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -134,6 +134,14 @@
when(mMockedResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat))
.thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[1]);
+ when(mMockedResources.getStringArray(R.array.config_displayUniqueIdArray))
+ .thenReturn(new String[]{});
+ TypedArray mockArray = mock(TypedArray.class);
+ when(mockArray.length()).thenReturn(0);
+ when(mMockedResources.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray))
+ .thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_waterfallCutoutArray))
+ .thenReturn(mockArray);
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 697451e..a94f0ee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -881,6 +881,7 @@
// * E jobs test that expedited jobs don't skip the line when the app has no regular jobs
// * F jobs test correct expedited/regular ordering doesn't push jobs too high in list
// * G jobs test correct ordering for regular jobs
+ // * H job tests correct behavior when enqueue times are the same
JobStatus rA1 = createJobStatus("testPendingJobSorting", createJobInfo(1), 1);
JobStatus rB2 = createJobStatus("testPendingJobSorting", createJobInfo(2), 2);
JobStatus eC3 = createJobStatus("testPendingJobSorting",
@@ -892,6 +893,7 @@
createJobInfo(6).setExpedited(true), 2);
JobStatus eA7 = createJobStatus("testPendingJobSorting",
createJobInfo(7).setExpedited(true), 1);
+ JobStatus rH8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 14);
JobStatus rF8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 6);
JobStatus eF9 = createJobStatus("testPendingJobSorting",
createJobInfo(9).setExpedited(true), 6);
@@ -911,6 +913,7 @@
eB6.enqueueTime = 6;
eA7.enqueueTime = 7;
rF8.enqueueTime = 8;
+ rH8.enqueueTime = 8;
eF9.enqueueTime = 9;
rC10.enqueueTime = 10;
eC11.enqueueTime = 11;
@@ -927,6 +930,7 @@
mService.mPendingJobs.add(rD4);
mService.mPendingJobs.add(eA7);
mService.mPendingJobs.add(rG12);
+ mService.mPendingJobs.add(rH8);
mService.mPendingJobs.add(rF8);
mService.mPendingJobs.add(eB6);
mService.mPendingJobs.add(eE14);
@@ -939,7 +943,7 @@
mService.mPendingJobs.sort(mService.mPendingJobComparator);
final JobStatus[] expectedOrder = new JobStatus[]{
- eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rF8, eC11, rC10, rG12, rG13, eE14};
+ eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rH8, rF8, eC11, rC10, rG12, rG13, eE14};
for (int i = 0; i < expectedOrder.length; ++i) {
assertEquals("List wasn't correctly sorted @ index " + i,
expectedOrder[i].getJobId(), mService.mPendingJobs.get(i).getJobId());
@@ -991,7 +995,7 @@
for (int i = 0; i < 2500; ++i) {
JobStatus job = createJobStatus("testPendingJobSorting_Random",
createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(250));
- job.enqueueTime = Math.abs(random.nextInt(1_000_000));
+ job.enqueueTime = random.nextInt(1_000_000);
mService.mPendingJobs.add(job);
mService.mPendingJobComparator.refreshLocked();
@@ -1019,18 +1023,48 @@
@Test
public void testPendingJobSortingTransitivity() {
- Random random = new Random(1); // Always use the same series of pseudo random values.
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+ Random random = new Random(seed);
- mService.mPendingJobs.clear();
+ mService.mPendingJobs.clear();
- for (int i = 0; i < 250; ++i) {
- JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
- createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
- job.enqueueTime = Math.abs(random.nextInt(1_000_000));
- job.overrideState = random.nextInt(4);
- mService.mPendingJobs.add(job);
+ for (int i = 0; i < 300; ++i) {
+ JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
+ createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
+ job.enqueueTime = random.nextInt(1_000_000);
+ job.overrideState = random.nextInt(4);
+ mService.mPendingJobs.add(job);
+ }
+
+ verifyPendingJobComparatorTransitivity();
}
+ }
+ @Test
+ public void testPendingJobSortingTransitivity_Concentrated() {
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+ Random random = new Random(seed);
+
+ mService.mPendingJobs.clear();
+
+ for (int i = 0; i < 300; ++i) {
+ JobStatus job = createJobStatus("testPendingJobSortingTransitivity_Concentrated",
+ createJobInfo(i).setExpedited(random.nextFloat() < .03),
+ random.nextInt(20));
+ job.enqueueTime = random.nextInt(250);
+ job.overrideState = random.nextFloat() < .01
+ ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+ mService.mPendingJobs.add(job);
+ Log.d(TAG, sortedJobToString(job));
+ }
+
+ verifyPendingJobComparatorTransitivity();
+ }
+ }
+
+ private void verifyPendingJobComparatorTransitivity() {
mService.mPendingJobComparator.refreshLocked();
for (int i = 0; i < mService.mPendingJobs.size(); ++i) {
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/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
new file mode 100644
index 0000000..f94377f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED;
+import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.testing.TestableContext;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.testables.TestableDeviceConfig;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.server.power.ScreenUndimDetector}
+ */
+@RunWith(JUnit4.class)
+public class ScreenUndimDetectorTest {
+ private static final List<Integer> ALL_POLICIES =
+ Arrays.asList(POLICY_OFF,
+ POLICY_DOZE,
+ POLICY_DIM,
+ POLICY_BRIGHT,
+ POLICY_VR);
+
+ @ClassRule
+ public static final TestableContext sContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public TestableDeviceConfig.TestableDeviceConfigRule
+ mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+ private ScreenUndimDetector mScreenUndimDetector;
+
+ private final TestClock mClock = new TestClock();
+
+ private static class TestClock extends ScreenUndimDetector.InternalClock {
+ long mCurrentTime = 0;
+ @Override
+ public long getCurrentTime() {
+ return mCurrentTime;
+ }
+
+ public void advanceTime(long millisAdvanced) {
+ mCurrentTime += millisAdvanced;
+ }
+ }
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(1), false /*makeDefault*/);
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+ Long.toString(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS),
+ false /*makeDefault*/);
+
+ mScreenUndimDetector = new ScreenUndimDetector(mClock);
+ mScreenUndimDetector.systemReady(sContext);
+ }
+
+ @Test
+ public void recordScreenPolicy_disabledByFlag_noop() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/);
+
+ setup();
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ }
+
+ @Test
+ public void recordScreenPolicy_samePolicy_noop() {
+ for (int policy : ALL_POLICIES) {
+ setup();
+ mScreenUndimDetector.recordScreenPolicy(policy);
+ mScreenUndimDetector.recordScreenPolicy(policy);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ }
+ }
+
+ @Test
+ public void recordScreenPolicy_dimToBright_extends() {
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+ }
+
+ @Test
+ public void recordScreenPolicy_otherTransitions_doesNotExtend() {
+ for (int from : ALL_POLICIES) {
+ for (int to : ALL_POLICIES) {
+ if (from == POLICY_DIM && to == POLICY_BRIGHT) {
+ continue;
+ }
+ setup();
+ mScreenUndimDetector.recordScreenPolicy(from);
+ mScreenUndimDetector.recordScreenPolicy(to);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+ }
+ }
+ }
+
+ @Test
+ public void recordScreenPolicy_dimToBright_twoUndimsNeeded_extends() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(2), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+ }
+
+ @Test
+ public void recordScreenPolicy_dimBrightDimOff_resetsCounter_doesNotExtend() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(2), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+ }
+
+ @Test
+ public void recordScreenPolicy_undimToOff_resetsCounter() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(2), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+ }
+
+ @Test
+ public void recordScreenPolicy_undimOffUndim_doesNotExtend() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(2), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ // undim
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ // off
+ mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+ // second undim
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+ }
+
+ @Test
+ public void recordScreenPolicy_dimToBright_tooFarApart_doesNotExtend() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(2), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ mClock.advanceTime(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS + 5);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+ }
+
+ @Test
+ public void recordScreenPolicy_dimToNonBright_resets() {
+ for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+ setup();
+ mScreenUndimDetector.mUndimCounter = 1;
+ mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+ mScreenUndimDetector.mWakeLock.acquire();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+ mScreenUndimDetector.recordScreenPolicy(to);
+
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+ assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ }
+
+ }
+
+ @Test
+ public void recordScreenPolicy_brightToNonDim_resets() {
+ for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+ setup();
+ mScreenUndimDetector.mUndimCounter = 1;
+ mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+ mScreenUndimDetector.mWakeLock.acquire();
+
+ mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+ mScreenUndimDetector.recordScreenPolicy(to);
+
+ assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+ assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+ assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+ }
+ }
+
+ @Test
+ public void recordScreenPolicy_otherTransitions_doesNotReset() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_UNDIMS_REQUIRED,
+ Integer.toString(3),
+ false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
+
+ for (int from : ALL_POLICIES) {
+ for (int to : ALL_POLICIES) {
+ if (from == POLICY_DIM && to != POLICY_BRIGHT) {
+ continue;
+ }
+ if (from == POLICY_BRIGHT && to != POLICY_DIM) {
+ continue;
+ }
+ mScreenUndimDetector.mCurrentScreenPolicy = POLICY_OFF;
+ mScreenUndimDetector.mUndimCounter = 1;
+ mScreenUndimDetector.mUndimCounterStartedMillis =
+ SystemClock.currentThreadTimeMillis();
+
+ mScreenUndimDetector.recordScreenPolicy(from);
+ mScreenUndimDetector.recordScreenPolicy(to);
+
+ assertThat(mScreenUndimDetector.mUndimCounter).isNotEqualTo(0);
+ assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isNotEqualTo(0);
+ }
+ }
+ }
+}
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 1a3e53e..b403033 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -16,6 +16,8 @@
package com.android.server.accessibility;
+import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
+
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static junit.framework.Assert.assertFalse;
@@ -46,6 +48,7 @@
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SigningInfo;
@@ -59,6 +62,7 @@
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.R;
+import com.android.server.LocalServices;
import org.junit.Before;
import org.junit.Rule;
@@ -84,10 +88,8 @@
private static final int APP_PID = 2000;
private static final int SYSTEM_PID = 558;
private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
- private static final String TEST_PACKAGE_NAME = "com.android.server.accessibility";
private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
- TEST_PACKAGE_NAME, "AccessibilitySecurityPolicyTest");
- private static final String ALLOWED_INSTALL_PACKAGE_NAME = "com.allowed.install.package";
+ "com.android.server.accessibility", "AccessibilitySecurityPolicyTest");
private static final int[] ALWAYS_DISPATCH_EVENTS = {
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
@@ -158,6 +160,8 @@
private PackageInfo mMockSourcePackageInfo;
@Mock
private PolicyWarningUIController mPolicyWarningUIController;
+ @Mock
+ private PackageManagerInternal mPackageManagerInternal;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
@@ -167,20 +171,6 @@
mContext.addMockSystemService(Context.APP_OPS_SERVICE, mMockAppOpsManager);
mContext.getOrCreateTestableResources().addOverride(
R.dimen.accessibility_focus_highlight_stroke_width, 1);
- mContext.getOrCreateTestableResources().addOverride(R.array
- .config_accessibility_allowed_install_source,
- new String[]{ALLOWED_INSTALL_PACKAGE_NAME});
-
- when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
- when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
- when(mMockA11yServiceConnection.getServiceInfo()).thenReturn(mMockA11yServiceInfo);
- when(mMockPackageManager.getPackageInfo(ALLOWED_INSTALL_PACKAGE_NAME, 0)).thenReturn(
- mMockSourcePackageInfo);
-
- mMockResolveInfo.serviceInfo = mMockServiceInfo;
- mMockServiceInfo.applicationInfo = mMockApplicationInfo;
- mMockServiceInfo.packageName = TEST_PACKAGE_NAME;
- mMockSourcePackageInfo.applicationInfo = mMockSourceApplicationInfo;
mA11ySecurityPolicy = new AccessibilitySecurityPolicy(
mPolicyWarningUIController, mContext, mMockA11yUserManager);
@@ -621,92 +611,148 @@
}
@Test
- public void onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction() {
+ public void onBoundServicesChanged_nonA11yTool_invokeAction()
+ throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
- when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false);
+ initServiceInfoAndConnection(TEST_COMPONENT_NAME,
+ mMockA11yServiceConnection,
+ /* isAccessibilityTool= */ false);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
-
verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID),
eq(TEST_COMPONENT_NAME));
- }
-
- @Test
- public void onBoundServicesChanged_unbindNonA11yToolService_activateUIControllerAction() {
- onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction();
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
-
verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID),
eq(TEST_COMPONENT_NAME));
}
@Test
- public void onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction() {
+ public void onBoundServicesChanged_sysA11yTool_noAction()
+ throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+ initServiceInfoAndConnection(TEST_COMPONENT_NAME,
+ mMockA11yServiceConnection,
+ /* isAccessibilityTool= */ true,
+ /* isSystemApp= */true,
+ /* installSourceInfo= */ null);
boundServices.add(mMockA11yServiceConnection);
- when(mMockApplicationInfo.isSystemApp()).thenReturn(true);
- when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
-
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
- }
-
- @Test
- public void onBoundServicesChanged_unbindSystemA11yToolService_noUIControllerAction() {
- onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction();
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
-
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
any());
}
@Test
- public void onBoundServicesChanged_bindAllowedSourceA11yToolService_noUIControllerAction()
+ public void onBoundServicesChanged_nonSysA11yToolFromAllowedInstallerInAllowedList_noAction()
throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+ final String allowedSourcePackageName = "com.allowed.install.package";
+ mContext.getOrCreateTestableResources().addOverride(R.array
+ .config_accessibility_allowed_install_source,
+ new String[]{allowedSourcePackageName});
+ // The allowed Installer should be system app in the allowed list.
+ InstallSourceInfo allowedSource = initInstallSourceInfo(
+ allowedSourcePackageName, /* isSystemApp= */ true);
+ initServiceInfoAndConnection(TEST_COMPONENT_NAME,
+ mMockA11yServiceConnection,
+ /* isAccessibilityTool= */ true,
+ /* isSystemApp= */ false,
+ allowedSource);
boundServices.add(mMockA11yServiceConnection);
- when(mMockApplicationInfo.isSystemApp()).thenReturn(false);
- final InstallSourceInfo installSourceInfo = new InstallSourceInfo(
- ALLOWED_INSTALL_PACKAGE_NAME, new SigningInfo(), null,
- ALLOWED_INSTALL_PACKAGE_NAME);
- when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn(
- installSourceInfo);
- when(mMockSourceApplicationInfo.isSystemApp()).thenReturn(true);
- when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
-
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
+
+ mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
+ verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
+ any());
}
@Test
- public void onBoundServicesChanged_bindUnknownSourceA11yToolService_activateUIControllerAction()
+ public void onBoundServicesChanged_nonSysA11yToolFromValidInstallerWithoutAllowedList_noAction()
throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+ final String validInstallerPackageName = "com.valid.install.package";
+ final String defaultInstallerPackageName = "com.default.install.package";
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
+ when(mPackageManagerInternal.getKnownPackageNames(PACKAGE_INSTALLER,
+ TEST_USER_ID)).thenReturn(new String[]{defaultInstallerPackageName});
+ mContext.getOrCreateTestableResources().addOverride(R.array
+ .config_accessibility_allowed_install_source,
+ new String[]{});
+ // The valid Installer should be system app and not the default installer.
+ InstallSourceInfo validSource = initInstallSourceInfo(
+ validInstallerPackageName, /* isSystemApp= */ true);
+ initServiceInfoAndConnection(TEST_COMPONENT_NAME,
+ mMockA11yServiceConnection, /* isAccessibilityTool= */ true,
+ /* isSystemApp= */ false,
+ validSource);
boundServices.add(mMockA11yServiceConnection);
- when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
- final InstallSourceInfo installSourceInfo = new InstallSourceInfo(null, null, null, null);
- when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn(
- installSourceInfo);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
+ verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
+ mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
+ verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
+ any());
+ }
+
+ @Test
+ public void onSwitchUser_oldUserHadAction_invokeActionForOldUser()
+ throws PackageManager.NameNotFoundException {
+ final int newUserId = 2;
+ final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+ initServiceInfoAndConnection(TEST_COMPONENT_NAME,
+ mMockA11yServiceConnection,
+ /* isAccessibilityTool= */ false);
+ boundServices.add(mMockA11yServiceConnection);
+ mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID),
eq(TEST_COMPONENT_NAME));
- }
- @Test
- public void onSwitchUser_differentUser_activateUIControllerAction() {
- onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction();
+ mA11ySecurityPolicy.onSwitchUserLocked(newUserId, new HashSet<>());
- mA11ySecurityPolicy.onSwitchUserLocked(2, new HashSet<>());
-
- verify(mPolicyWarningUIController).onSwitchUserLocked(eq(2), eq(new HashSet<>()));
+ verify(mPolicyWarningUIController).onSwitchUserLocked(eq(newUserId), eq(new HashSet<>()));
verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID),
eq(TEST_COMPONENT_NAME));
}
+
+ private void initServiceInfoAndConnection(ComponentName componentName,
+ AccessibilityServiceConnection connection,
+ boolean isAccessibilityTool) throws PackageManager.NameNotFoundException {
+ initServiceInfoAndConnection(componentName, connection, isAccessibilityTool, false, null);
+ }
+
+ private void initServiceInfoAndConnection(ComponentName componentName,
+ AccessibilityServiceConnection connection,
+ boolean isAccessibilityTool, boolean isSystemApp, InstallSourceInfo installSourceInfo)
+ throws PackageManager.NameNotFoundException {
+ when(connection.getServiceInfo()).thenReturn(mMockA11yServiceInfo);
+ when(mMockA11yServiceInfo.getComponentName()).thenReturn(componentName);
+ when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(isAccessibilityTool);
+ when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
+ mMockResolveInfo.serviceInfo = mMockServiceInfo;
+ mMockServiceInfo.applicationInfo = mMockApplicationInfo;
+ mMockServiceInfo.packageName = componentName.getPackageName();
+ when(mMockApplicationInfo.isSystemApp()).thenReturn(isSystemApp);
+ when(mMockPackageManager.getInstallSourceInfo(componentName.getPackageName())).thenReturn(
+ installSourceInfo);
+ }
+
+ private InstallSourceInfo initInstallSourceInfo(String packageName, boolean isSystemApp)
+ throws PackageManager.NameNotFoundException {
+ final InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ packageName, new SigningInfo(), null,
+ packageName);
+ when(mMockPackageManager.getPackageInfo(packageName, 0)).thenReturn(
+ mMockSourcePackageInfo);
+ mMockSourcePackageInfo.applicationInfo = mMockSourceApplicationInfo;
+ when(mMockSourceApplicationInfo.isSystemApp()).thenReturn(isSystemApp);
+ return installSourceInfo;
+ }
}
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..8592166a 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
@@ -360,7 +360,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
@@ -372,6 +373,11 @@
protected void startHalOperation() {
}
+
+ @Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+
+ }
}
private static class TestAuthenticationClient extends AuthenticationClient<Object> {
@@ -383,7 +389,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
@@ -395,6 +402,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 9c42f45..7f5f3c2 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
@@ -17,8 +17,12 @@
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_FP_OTHER;
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;
@@ -28,8 +32,11 @@
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;
@@ -39,6 +46,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.LinkedList;
+
@Presubmit
@SmallTest
public class CoexCoordinatorTest {
@@ -46,6 +55,7 @@
private static final String TAG = "CoexCoordinatorTest";
private CoexCoordinator mCoexCoordinator;
+ private Handler mHandler;
@Mock
private Context mContext;
@@ -55,8 +65,12 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ mHandler = new Handler(Looper.getMainLooper());
+
mCoexCoordinator = CoexCoordinator.getInstance();
mCoexCoordinator.setAdvancedLogicEnabled(true);
+ mCoexCoordinator.setFaceHapticDisabledWhenNonBypass(true);
}
@Test
@@ -68,9 +82,10 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
- mCoexCoordinator.onAuthenticationSucceeded(client, mCallback);
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, client, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
@@ -82,9 +97,11 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
- mCoexCoordinator.onAuthenticationRejected(client, LockoutTracker.LOCKOUT_NONE, mCallback);
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
+ client, LockoutTracker.LOCKOUT_NONE, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
@@ -96,9 +113,11 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
- mCoexCoordinator.onAuthenticationRejected(client, LockoutTracker.LOCKOUT_TIMED, mCallback);
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
+ client, LockoutTracker.LOCKOUT_TIMED, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
@@ -110,9 +129,10 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
- mCoexCoordinator.onAuthenticationSucceeded(client, mCallback);
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, client, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
@@ -130,13 +150,97 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
- mCoexCoordinator.onAuthenticationSucceeded(faceClient, mCallback);
- verify(mCallback).sendHapticFeedback();
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+ mCallback);
+ // Haptics tested in #testKeyguard_bypass_haptics. Let's leave this commented out (instead
+ // of removed) to keep this context.
+ // verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
- public void testKeyguard_faceAuth_udfpsTouching_faceSuccess() {
+ public void testKeyguard_faceAuthSuccess_nonBypass_udfpsRunning_noHaptics() {
+ testKeyguard_bypass_haptics(false /* bypassEnabled */,
+ true /* faceAccepted */,
+ false /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthReject_nonBypass_udfpsRunning_noHaptics() {
+ testKeyguard_bypass_haptics(false /* bypassEnabled */,
+ false /* faceAccepted */,
+ false /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthSuccess_bypass_udfpsRunning_haptics() {
+ testKeyguard_bypass_haptics(true /* bypassEnabled */,
+ true /* faceAccepted */,
+ true /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthReject_bypass_udfpsRunning_haptics() {
+ testKeyguard_bypass_haptics(true /* bypassEnabled */,
+ false /* faceAccepted */,
+ true /* shouldReceiveHaptics */);
+ }
+
+ private void testKeyguard_bypass_haptics(boolean bypassEnabled, boolean faceAccepted,
+ boolean shouldReceiveHaptics) {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+
+ 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);
+
+ if (faceAccepted) {
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+ mCallback);
+ } else {
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ }
+
+ if (shouldReceiveHaptics) {
+ verify(mCallback).sendHapticFeedback();
+ } else {
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ verify(mCallback).sendAuthenticationResult(eq(faceAccepted) /* 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);
@@ -146,13 +250,54 @@
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(faceClient, mCallback);
+ 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
@@ -161,6 +306,7 @@
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));
@@ -170,9 +316,173 @@
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
- mCoexCoordinator.onAuthenticationSucceeded(udfpsClient, mCallback);
+ 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_noKeyguardBypass() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(faceClient.isKeyguardBypassEnabled()).thenReturn(false); // TODO: also test "true" case
+
+ 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);
+ // Auth was attempted
+ when(udfpsClient.getState())
+ .thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED);
+ 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 testKeyguard_capacitiveAccepted_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, fpClient, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_capacitiveRejected_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, fpClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @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/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index a38a84b..88f70af 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -139,10 +139,14 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage menuStatus = HdmiCecMessageBuilder.buildReportMenuStatus(
- playbackDevice.mAddress, ADDR_TV, Constants.MENU_STATE_ACTIVATED);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage menuStatus =
+ HdmiCecMessageBuilder.buildReportMenuStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ Constants.MENU_STATE_ACTIVATED);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(menuStatus);
@@ -162,8 +166,8 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
- playbackDevice.mAddress);
+ assertThat(playbackDevice.getActiveSource().logicalAddress)
+ .isEqualTo(playbackDevice.getDeviceInfo().getLogicalAddress());
assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
assertThat(playbackDevice.isActiveSource()).isTrue();
}
@@ -182,10 +186,14 @@
audioDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(audioDevice.mAddress,
- mPhysicalAddress);
- HdmiCecMessage menuStatus = HdmiCecMessageBuilder.buildReportMenuStatus(
- audioDevice.mAddress, ADDR_TV, Constants.MENU_STATE_ACTIVATED);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ audioDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage menuStatus =
+ HdmiCecMessageBuilder.buildReportMenuStatus(
+ audioDevice.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ Constants.MENU_STATE_ACTIVATED);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(menuStatus);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
index f49b1c1..9c99240 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
@@ -73,7 +73,9 @@
mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
HdmiCecMessageBuilder.buildFeatureAbortCommand(
Constants.ADDR_TV,
- mHdmiCecLocalDeviceAudioSystem.mAddress,
+ mHdmiCecLocalDeviceAudioSystem
+ .getDeviceInfo()
+ .getLogicalAddress(),
Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE,
Constants.ABORT_UNRECOGNIZED_OPCODE));
}
@@ -106,6 +108,7 @@
}
};
mHdmiCecLocalDeviceAudioSystem.init();
+ mHdmiCecLocalDeviceAudioSystem.setDeviceInfo(mDeviceInfoForTests);
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index fe8d691..57756f9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -150,12 +150,16 @@
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
mTestLooper.dispatchAll();
- HdmiCecMessage expected = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage expected =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(expected);
- HdmiCecMessage response = HdmiCecMessageBuilder.buildReportPowerStatus(
- ADDR_TV, mPlaybackDevice.mAddress, HdmiControlManager.POWER_STATUS_STANDBY);
+ HdmiCecMessage response =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ ADDR_TV,
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_STANDBY);
mNativeWrapper.onCecMessage(response);
mTestLooper.dispatchAll();
@@ -177,8 +181,9 @@
public void queryDisplayStatus_sendsRequest_timeout_retriesSuccessfully() throws Exception {
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
- HdmiCecMessage expected = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage expected =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(expected);
@@ -188,8 +193,11 @@
assertThat(mNativeWrapper.getResultMessages()).contains(expected);
- HdmiCecMessage response = HdmiCecMessageBuilder.buildReportPowerStatus(
- ADDR_TV, mPlaybackDevice.mAddress, HdmiControlManager.POWER_STATUS_STANDBY);
+ HdmiCecMessage response =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ ADDR_TV,
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_STANDBY);
mNativeWrapper.onCecMessage(response);
mTestLooper.dispatchAll();
@@ -201,8 +209,9 @@
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
mTestLooper.dispatchAll();
- HdmiCecMessage expected = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage expected =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(expected);
mNativeWrapper.clearResultMessages();
mTestLooper.moveTimeForward(TIMEOUT_MS);
@@ -225,12 +234,16 @@
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
- HdmiCecMessage response = HdmiCecMessageBuilder.buildReportPowerStatus(
- ADDR_TV, mPlaybackDevice.mAddress, HdmiControlManager.POWER_STATUS_STANDBY);
+ HdmiCecMessage response =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ ADDR_TV,
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_STANDBY);
mNativeWrapper.onCecMessage(response);
mTestLooper.dispatchAll();
@@ -254,8 +267,9 @@
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
verify(mCallbackMock).onComplete(HdmiControlManager.POWER_STATUS_STANDBY);
@@ -278,12 +292,16 @@
mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
- HdmiCecMessage response = HdmiCecMessageBuilder.buildReportPowerStatus(
- ADDR_TV, mPlaybackDevice.mAddress, HdmiControlManager.POWER_STATUS_STANDBY);
+ HdmiCecMessage response =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ ADDR_TV,
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_STANDBY);
mNativeWrapper.onCecMessage(response);
mTestLooper.dispatchAll();
@@ -298,8 +316,9 @@
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
- mPlaybackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessage =
+ HdmiCecMessageBuilder.buildStandby(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index e03e1be..7eb8990 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -795,12 +795,13 @@
@Test
public void setActiveSource_localDevice_playback() {
- mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
+ mHdmiControlService.setActiveSource(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
SELF_PHYSICAL_ADDRESS,
"HdmiControlServiceTest");
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- mHdmiCecLocalDevicePlayback.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress)
+ .isEqualTo(mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
SELF_PHYSICAL_ADDRESS);
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
@@ -809,12 +810,13 @@
@Test
public void setActiveSource_localDevice_audio() {
- mHdmiControlService.setActiveSource(mHdmiCecLocalDeviceAudioSystem.mAddress,
+ mHdmiControlService.setActiveSource(
+ mHdmiCecLocalDeviceAudioSystem.getDeviceInfo().getLogicalAddress(),
SELF_PHYSICAL_ADDRESS,
"HdmiControlServiceTest");
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- mHdmiCecLocalDeviceAudioSystem.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress)
+ .isEqualTo(mHdmiCecLocalDeviceAudioSystem.getDeviceInfo().getLogicalAddress());
assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
SELF_PHYSICAL_ADDRESS);
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 99e3d68..337276d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -657,7 +657,9 @@
// Test should ignore it and still keep the system audio mode on.
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetSystemAudioMode(
- Constants.ADDR_AUDIO_SYSTEM, mHdmiCecLocalDevicePlayback.mAddress, false);
+ Constants.ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ false);
assertThat(mHdmiCecLocalDevicePlayback.handleSetSystemAudioMode(message))
.isEqualTo(Constants.HANDLED);
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isTrue();
@@ -669,7 +671,9 @@
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse();
HdmiCecMessage message =
HdmiCecMessageBuilder.buildReportSystemAudioMode(
- Constants.ADDR_AUDIO_SYSTEM, mHdmiCecLocalDevicePlayback.mAddress, true);
+ Constants.ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ true);
assertThat(mHdmiCecLocalDevicePlayback.handleSystemAudioModeStatus(message))
.isEqualTo(Constants.HANDLED);
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isTrue();
@@ -699,12 +703,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -724,12 +733,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -749,12 +763,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -774,12 +793,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -799,12 +823,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -824,12 +853,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -849,12 +883,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -874,12 +913,17 @@
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageToAudioSystem =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -899,10 +943,13 @@
mHdmiCecLocalDevicePlayback.onStandby(true, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageToTv =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
@@ -1119,8 +1166,10 @@
HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
mStandby = false;
// 1. DUT is <AS>.
- HdmiCecMessage message1 = HdmiCecMessageBuilder.buildActiveSource(
- mHdmiCecLocalDevicePlayback.mAddress, mPlaybackPhysicalAddress);
+ HdmiCecMessage message1 =
+ HdmiCecMessageBuilder.buildActiveSource(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message1))
.isEqualTo(Constants.HANDLED);
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
@@ -1137,16 +1186,20 @@
mPlaybackPhysicalAddress);
mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- mHdmiCecLocalDevicePlayback.mAddress, mPlaybackPhysicalAddress);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ mPlaybackPhysicalAddress);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mWokenUp).isTrue();
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
// 4. DUT turned off.
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+ HdmiCecMessage standbyMessageBroadcast =
+ HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_BROADCAST);
assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageBroadcast);
}
@@ -1158,11 +1211,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
@@ -1176,11 +1232,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
@@ -1194,11 +1253,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_MUTE);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_MUTE);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
@@ -1212,11 +1274,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
@@ -1230,11 +1295,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
@@ -1248,11 +1316,14 @@
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
mTestLooper.dispatchAll();
- HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
- HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
- HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
- mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage keyPressed =
+ HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased =
+ HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
@@ -1347,8 +1418,10 @@
mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- mHdmiCecLocalDevicePlayback.mAddress, mPlaybackPhysicalAddress);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ mPlaybackPhysicalAddress);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
}
@@ -1606,8 +1679,10 @@
@Test
public void getActiveSource_localPlaybackIsActiveSource() {
- mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
- mHdmiControlService.getPhysicalAddress(), "HdmiControlServiceTest");
+ mHdmiControlService.setActiveSource(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ mHdmiControlService.getPhysicalAddress(),
+ "HdmiControlServiceTest");
assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
mHdmiCecLocalDevicePlayback.getDeviceInfo());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 6c2db36..2f72809 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -386,9 +386,13 @@
@Test
public void handleCecVersion_isHandled() {
- @Constants.HandleMessageResult int result = mHdmiLocalDevice.onMessage(
- HdmiCecMessageBuilder.buildCecVersion(ADDR_PLAYBACK_1, mHdmiLocalDevice.mAddress,
- HdmiControlManager.HDMI_CEC_VERSION_1_4_B));
+ @Constants.HandleMessageResult
+ int result =
+ mHdmiLocalDevice.onMessage(
+ HdmiCecMessageBuilder.buildCecVersion(
+ ADDR_PLAYBACK_1,
+ mHdmiLocalDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_B));
assertEquals(Constants.HANDLED, result);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 5a2f7bb..a0fcd83 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -515,8 +515,11 @@
HdmiCecFeatureAction systemAudioAutoInitiationAction =
new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -548,8 +551,11 @@
new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index dc633a2..ceb41cf 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -184,9 +184,11 @@
mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@@ -197,9 +199,11 @@
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@@ -210,9 +214,11 @@
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@@ -222,9 +228,11 @@
mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_ON);
assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
}
@@ -235,9 +243,11 @@
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
}
@@ -248,9 +258,11 @@
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
- HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
+ Constants.ADDR_BROADCAST,
+ HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 755eef3..2704308 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -735,9 +735,11 @@
mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_TV,
- mHdmiControlServiceSpy.playback().mAddress, HdmiControlManager.POWER_STATUS_ON);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV,
+ mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_ON);
mNativeWrapper.onCecMessage(reportPowerStatus);
mTestLooper.dispatchAll();
@@ -756,10 +758,11 @@
mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_TV,
- mHdmiControlServiceSpy.playback().mAddress,
- HdmiControlManager.POWER_STATUS_STANDBY);
+ HdmiCecMessage reportPowerStatus =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV,
+ mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_STANDBY);
mNativeWrapper.onCecMessage(reportPowerStatus);
mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 9466f52..d5b116f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -175,20 +175,27 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
- HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ HdmiCecMessage reportPowerStatusOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_ON);
action.processCommand(reportPowerStatusOn);
mTestLooper.dispatchAll();
@@ -218,20 +225,27 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
- HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ HdmiCecMessage reportPowerStatusOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_ON);
action.processCommand(reportPowerStatusOn);
mTestLooper.dispatchAll();
@@ -261,21 +275,27 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
- HdmiCecMessage reportPowerStatusTransientToOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS,
- POWER_TRANSIENT_TO_ON);
+ HdmiCecMessage reportPowerStatusTransientToOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_TRANSIENT_TO_ON);
action.processCommand(reportPowerStatusTransientToOn);
action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS);
mTestLooper.dispatchAll();
@@ -283,8 +303,12 @@
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
- HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ HdmiCecMessage reportPowerStatusOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_ON);
action.processCommand(reportPowerStatusOn);
mTestLooper.dispatchAll();
@@ -314,12 +338,15 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
@@ -360,12 +387,15 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
@@ -395,20 +425,27 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
- HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ HdmiCecMessage reportPowerStatusOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_ON);
action.processCommand(reportPowerStatusOn);
mTestLooper.dispatchAll();
@@ -440,20 +477,27 @@
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
- .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
mNativeWrapper.clearResultMessages();
assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
- HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
- ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ HdmiCecMessage reportPowerStatusOn =
+ new HdmiCecMessage(
+ ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ Constants.MESSAGE_REPORT_POWER_STATUS,
+ POWER_ON);
action.processCommand(reportPowerStatusOn);
mTestLooper.dispatchAll();
@@ -487,11 +531,11 @@
mTestLooper.dispatchAll();
- HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_TV,
- playbackDevice.mAddress,
- HdmiControlManager.POWER_STATUS_ON
- );
+ HdmiCecMessage reportPowerStatusMessage =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_ON);
mNativeWrapper.onCecMessage(reportPowerStatusMessage);
mTestLooper.dispatchAll();
@@ -499,10 +543,12 @@
assertThat(mHdmiControlService.isAddressAllocated()).isTrue();
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@@ -523,21 +569,23 @@
TestCallback callback = new TestCallback();
mHdmiControlService.oneTouchPlay(callback);
- HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_TV,
- playbackDevice.mAddress,
- HdmiControlManager.POWER_STATUS_ON
- );
+ HdmiCecMessage reportPowerStatusMessage =
+ HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV,
+ playbackDevice.getDeviceInfo().getLogicalAddress(),
+ HdmiControlManager.POWER_STATUS_ON);
mNativeWrapper.onCecMessage(reportPowerStatusMessage);
mTestLooper.dispatchAll();
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
- HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
- playbackDevice.mAddress, mPhysicalAddress);
- HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
- ADDR_TV);
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@@ -574,8 +622,9 @@
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
- playbackDevice.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessage =
+ HdmiCecMessageBuilder.buildStandby(
+ playbackDevice.getDeviceInfo().getLogicalAddress(), ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index a9880c0..60c0f41 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -156,9 +156,9 @@
assertPowerStatus(ADDR_PLAYBACK_1, HdmiControlManager.POWER_STATUS_UNKNOWN);
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_1);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
reportPowerStatus(ADDR_PLAYBACK_1, false, HdmiControlManager.POWER_STATUS_ON);
@@ -195,9 +195,9 @@
assertPowerStatus(ADDR_PLAYBACK_1, HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_1);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
@@ -224,14 +224,14 @@
action.start();
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_1);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
- HdmiCecMessage giveDevicePowerStatus2 = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_2);
+ HdmiCecMessage giveDevicePowerStatus2 =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_2);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus2);
}
@@ -249,15 +249,15 @@
action.start();
mTestLooper.dispatchAll();
- HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_1);
+ HdmiCecMessage giveDevicePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
- HdmiCecMessage giveDevicePowerStatus2 = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
- mTvDevice.mAddress,
- ADDR_PLAYBACK_2);
+ HdmiCecMessage giveDevicePowerStatus2 =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), ADDR_PLAYBACK_2);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus2);
}
@@ -270,7 +270,8 @@
}
private void reportPowerStatus(int logicalAddress, boolean broadcast, int powerStatus) {
- int destination = broadcast ? ADDR_BROADCAST : mTvDevice.mAddress;
+ int destination =
+ broadcast ? ADDR_BROADCAST : mTvDevice.getDeviceInfo().getLogicalAddress();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
logicalAddress, destination,
powerStatus);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index 290e4b0..c650f4b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -167,12 +167,16 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -193,12 +197,16 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -217,12 +225,16 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, false);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ false);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -244,12 +256,16 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ true);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -271,12 +287,16 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
- HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
- ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, false);
+ HdmiCecMessage reportSystemAudioMode =
+ HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM,
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ false);
mHdmiControlService.handleCecCommand(reportSystemAudioMode);
mTestLooper.dispatchAll();
@@ -296,7 +316,8 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
mNativeWrapper.clearResultMessages();
@@ -321,7 +342,8 @@
HdmiCecMessage giveSystemAudioModeStatus =
HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
- mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+ ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
for (int i = 0; i < RETRIES_ON_TIMEOUT; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index 2019a16..3a8808b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -197,6 +197,7 @@
}
};
mHdmiCecLocalDeviceAudioSystem.init();
+ mHdmiCecLocalDeviceAudioSystem.setDeviceInfo(mDeviceInfoForTests);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 1b6bddc..15f57e3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -17,7 +17,8 @@
package com.android.server.pm;
-import android.content.pm.PackageParser;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
+
import android.content.pm.Signature;
import android.test.AndroidTestCase;
import android.util.ArrayMap;
@@ -60,11 +61,11 @@
assertEquals(0, aliases.size());
}
- /* test equivalence of PackageManager cert encoding and PackageParser manifest keys */
+ /* test equivalence of PackageManager cert encoding and ParsingPackageUtils manifest keys */
public void testPublicKeyCertReprEquiv() throws CertificateException {
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
- PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
Signature sigA = new Signature(KeySetStrings.ctsKeySetCertA);
Signature sigB = new Signature(KeySetStrings.ctsKeySetCertB);
@@ -99,9 +100,9 @@
new WatchedArrayMap<String, PackageSetting>();
KeySetManagerService ksms = new KeySetManagerService(packagesMap);
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
- PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
assertEquals(ksms.encodePublicKey(keyA), KeySetStrings.ctsKeySetPublicKeyA);
assertEquals(ksms.encodePublicKey(keyB), KeySetStrings.ctsKeySetPublicKeyB);
@@ -119,7 +120,7 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -146,7 +147,7 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -176,12 +177,12 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
/* now upgrade with new key */
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
signingKeys.removeAt(0);
signingKeys.add(keyB);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -213,13 +214,13 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
/* now upgrade with new key */
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
signingKeys.removeAt(0);
signingKeys.add(keyB);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
@@ -256,13 +257,13 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys1 = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys1.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys1);
/* collect second signing key and add */
ArraySet<PublicKey> signingKeys2 = new ArraySet<PublicKey>();
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
signingKeys2.add(keyB);
mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys2);
@@ -301,7 +302,7 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
@@ -334,12 +335,12 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
/* give ps2 a superset (add keyB) */
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
signingKeys.add(keyB);
mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
@@ -375,12 +376,12 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
/* now with additional key */
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
signingKeys.add(keyB);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -413,7 +414,7 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -440,7 +441,7 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
definedKS.put("aliasA2", keys);
@@ -470,14 +471,14 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
/* now upgrade to different defined key-set */
keys = new ArraySet<PublicKey>();
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
keys.add(keyB);
definedKS.remove("aliasA");
definedKS.put("aliasB", keys);
@@ -510,14 +511,14 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
/* now upgrade to different set w/same alias as before */
keys = new ArraySet<PublicKey>();
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
keys.add(keyB);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -548,8 +549,8 @@
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
keys1.add(keyA);
keys2.add(keyB);
definedKS.put("aliasA", keys1);
@@ -558,7 +559,7 @@
/* now upgrade to different set (B, C) */
keys1 = new ArraySet<PublicKey>();
- PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+ PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
keys1.add(keyC);
definedKS.remove("aliasA");
definedKS.put("aliasC", keys1);
@@ -612,14 +613,14 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys1.add(keyA);
definedKS.put("aliasA", keys1);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
/* now upgrade to different set */
ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
keys2.add(keyB);
definedKS.remove("aliasA");
definedKS.put("aliasB", keys2);
@@ -655,7 +656,7 @@
/* collect key and add, and denote as an upgrade keyset */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -677,7 +678,7 @@
/* collect key and add and try to specify bogus upgrade keyset */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -704,7 +705,7 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
definedKS.put("aliasA", keys);
mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -713,7 +714,7 @@
mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
keys = new ArraySet<PublicKey>();
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
keys.add(keyB);
definedKS.remove("aliasA");
definedKS.put("aliasB", keys);
@@ -730,7 +731,7 @@
/* collect signing key and add */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -755,7 +756,7 @@
/* collect signing key and add for both packages */
ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
signingKeys.add(keyA);
mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
@@ -781,7 +782,7 @@
/* collect key and add */
ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
keys.add(keyA);
/* removal requires signing keyset to be specified (since all apps are
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 976a588..f241fe1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -101,16 +101,15 @@
PackageSenderImpl sender = new PackageSenderImpl();
PackageSetting setting = null;
- PackageManagerService.PackageRemovedInfo pri =
- new PackageManagerService.PackageRemovedInfo(sender);
+ PackageRemovedInfo pri = new PackageRemovedInfo(sender);
// Initial conditions: nothing there
- Assert.assertNull(pri.removedUsers);
- Assert.assertNull(pri.broadcastUsers);
+ Assert.assertNull(pri.mRemovedUsers);
+ Assert.assertNull(pri.mBroadcastUsers);
// populateUsers with nothing leaves nothing
pri.populateUsers(null, setting);
- Assert.assertNull(pri.broadcastUsers);
+ Assert.assertNull(pri.mBroadcastUsers);
// Create a real (non-null) PackageSetting and confirm that the removed
// users are copied properly
@@ -126,22 +125,22 @@
pri.populateUsers(new int[] {
1, 2, 3, 4, 5
}, setting);
- Assert.assertNotNull(pri.broadcastUsers);
- Assert.assertEquals(5, pri.broadcastUsers.length);
- Assert.assertNotNull(pri.instantUserIds);
- Assert.assertEquals(0, pri.instantUserIds.length);
+ Assert.assertNotNull(pri.mBroadcastUsers);
+ Assert.assertEquals(5, pri.mBroadcastUsers.length);
+ Assert.assertNotNull(pri.mInstantUserIds);
+ Assert.assertEquals(0, pri.mInstantUserIds.length);
// Exclude a user
- pri.broadcastUsers = null;
+ pri.mBroadcastUsers = null;
final int EXCLUDED_USER_ID = 4;
setting.setInstantApp(true, EXCLUDED_USER_ID);
pri.populateUsers(new int[] {
1, 2, 3, EXCLUDED_USER_ID, 5
}, setting);
- Assert.assertNotNull(pri.broadcastUsers);
- Assert.assertEquals(4, pri.broadcastUsers.length);
- Assert.assertNotNull(pri.instantUserIds);
- Assert.assertEquals(1, pri.instantUserIds.length);
+ Assert.assertNotNull(pri.mBroadcastUsers);
+ Assert.assertEquals(4, pri.mBroadcastUsers.length);
+ Assert.assertNotNull(pri.mInstantUserIds);
+ Assert.assertEquals(1, pri.mInstantUserIds.length);
// TODO: test that sendApplicationHiddenForUser() actually fills in
// broadcastUsers
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 22fb76b..45e2ab4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -22,6 +22,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
import static android.content.res.Resources.ID_NULL;
import static org.hamcrest.CoreMatchers.is;
@@ -39,7 +40,6 @@
import android.app.PropertyInvalidatedCache;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
@@ -1216,9 +1216,9 @@
assertThat(KeySetUtils.getPubKeyRefCount(ksms, 3), is(1));
/* verify public keys properly read */
- PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
- PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
- PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+ PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+ PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+ PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
assertThat(KeySetUtils.getPubKey(ksms, 1), is(keyA));
assertThat(KeySetUtils.getPubKey(ksms, 2), is(keyB));
assertThat(KeySetUtils.getPubKey(ksms, 3), is(keyC));
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/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 12fb400..54bfe01 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -108,8 +108,8 @@
return this;
}
- PackageManagerService.ScanRequest build() {
- return new PackageManagerService.ScanRequest(
+ ScanRequest build() {
+ return new ScanRequest(
mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
mUser, mCpuAbiOverride);
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..6c6cfd4 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;
@@ -129,16 +129,16 @@
@Test
public void newInstallSimpleAllNominal() throws Exception {
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
- assertThat(scanResult.existingSettingCopied, is(false));
+ assertThat(scanResult.mExistingSettingCopied, is(false));
assertPathsNotDerived(scanResult);
}
@@ -147,38 +147,38 @@
final int[] userIds = {0, 10, 11};
when(mMockUserManager.getUserIds()).thenReturn(userIds);
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName(null)
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
for (int uid : userIds) {
- assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+ assertThat(scanResult.mPkgSetting.readUserState(uid).installed, is(true));
}
}
@Test
public void installRealPackageName() throws Exception {
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName("com.package.real")
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+ assertThat(scanResult.mPkgSetting.realName, is("com.package.real"));
- final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+ final ScanRequest scanRequestNoRealPkg =
createBasicScanRequestBuilder(
createBasicPackage(DUMMY_PACKAGE_NAME)
.setRealPackage("com.package.real"))
.build();
- final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
- assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+ final ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+ assertThat(scanResultNoReal.mPkgSetting.realName, nullValue());
}
@Test
@@ -189,25 +189,25 @@
.setPrimaryCpuAbiString("primaryCpuAbi")
.setSecondaryCpuAbiString("secondaryCpuAbi")
.build();
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.setPkgSetting(pkgSetting)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- assertThat(scanResult.existingSettingCopied, is(true));
+ assertThat(scanResult.mExistingSettingCopied, is(true));
// ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
- assertNotSame(pkgSetting, scanResult.pkgSetting);
+ assertNotSame(pkgSetting, scanResult.mPkgSetting);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
- assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
- assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
- assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+ assertThat(scanResult.mPkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+ assertThat(scanResult.mPkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+ assertThat(scanResult.mPkgSetting.cpuAbiOverrideString, nullValue());
assertPathsNotDerived(scanResult);
}
@@ -221,13 +221,13 @@
.setInstantAppUserState(0, true)
.build();
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
}
@@ -241,27 +241,27 @@
.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)
+ final ScanRequest scanRequest = new ScanRequestBuilder(pkg)
.setUser(UserHandle.of(0)).build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
- assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
- assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
- assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
- assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+ assertThat(scanResult.mStaticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+ assertThat(scanResult.mStaticSharedLibraryInfo.getName(), is("static.lib"));
+ assertThat(scanResult.mStaticSharedLibraryInfo.getLongVersion(), is(123L));
+ assertThat(scanResult.mStaticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+ assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
is("static.lib.pkg"));
- assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+ assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
is(pkg.getLongVersionCode()));
- assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+ assertThat(scanResult.mStaticSharedLibraryInfo.getAllCodePaths(),
hasItems("/some/path.apk", "/some/other/path.apk"));
- assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
- assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+ assertThat(scanResult.mStaticSharedLibraryInfo.getDependencies(), nullValue());
+ assertThat(scanResult.mStaticSharedLibraryInfo.getDependentPackages(), empty());
}
@Test
@@ -273,16 +273,16 @@
.hideAsParsed())
.setVersionCodeMajor(1)
.setVersionCode(234)
- .setBaseCodePath("/some/path.apk")
+ .setBaseApkPath("/some/path.apk")
.setSplitCodePaths(new String[] {"/some/other/path.apk"});
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+ final SharedLibraryInfo dynamicLib0 = scanResult.mDynamicSharedLibraryInfos.get(0);
assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
assertThat(dynamicLib0.getName(), is("liba"));
assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -295,7 +295,7 @@
assertThat(dynamicLib0.getDependencies(), nullValue());
assertThat(dynamicLib0.getDependentPackages(), empty());
- final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+ final SharedLibraryInfo dynamicLib1 = scanResult.mDynamicSharedLibraryInfos.get(1);
assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
assertThat(dynamicLib1.getName(), is("libb"));
assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -321,10 +321,10 @@
.hideAsParsed());
- final PackageManagerService.ScanResult scanResult = executeScan(
+ final ScanResult scanResult = executeScan(
new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
- assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
+ assertThat(scanResult.mPkgSetting.volumeUuid, is(UUID_TWO.toString()));
}
@Test
@@ -337,7 +337,7 @@
.hideAsParsed());
- final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+ final ScanResult scanResult = executeScan(new ScanRequestBuilder(
basicPackage)
.setPkgSetting(pkgSetting)
.addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -356,12 +356,12 @@
.hideAsParsed();
- final PackageManagerService.ScanResult result =
+ final ScanResult result =
executeScan(new ScanRequestBuilder(basicPackage)
.setOriginalPkgSetting(originalPkgSetting)
.build());
- assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
+ assertThat(result.mRequest.mParsedPackage.getPackageName(), is("original.package"));
}
@Test
@@ -373,14 +373,14 @@
.setInstantAppUserState(0, true)
.build();
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_FULL_APP)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
}
@@ -394,14 +394,14 @@
.setInstantAppUserState(0, false)
.build();
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_INSTANT_APP)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
}
@@ -413,17 +413,17 @@
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
.build();
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.setDisabledPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_NEW_INSTALL)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
- scanResult.pkgSetting);
+ int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
+ scanResult.mPkgSetting);
assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
}
@@ -432,14 +432,14 @@
final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
.addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
- final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+ final ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
createBasicScanRequestBuilder(basicPackage).build(),
mMockInjector,
true /*isUnderFactoryTest*/,
System.currentTimeMillis());
- int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
- scanResult.request.pkgSetting);
+ int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
+ scanResult.mRequest.mPkgSetting);
assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
}
@@ -449,13 +449,13 @@
.hideAsParsed())
.setSystem(true);
- final PackageManagerService.ScanRequest scanRequest =
+ final ScanRequest scanRequest =
createBasicScanRequestBuilder(pkg)
.build();
- final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+ final ScanResult scanResult = executeScan(scanRequest);
- assertThat(scanResult.pkgSetting.installSource.isOrphaned, is(true));
+ assertThat(scanResult.mPkgSetting.installSource.isOrphaned, is(true));
}
private static Matcher<Integer> hasFlag(final int flag) {
@@ -478,9 +478,9 @@
};
}
- private PackageManagerService.ScanResult executeScan(
- PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
- PackageManagerService.ScanResult result = PackageManagerService.scanPackageOnlyLI(
+ private ScanResult executeScan(
+ ScanRequest scanRequest) throws PackageManagerException {
+ ScanResult result = PackageManagerService.scanPackageOnlyLI(
scanRequest,
mMockInjector,
false /*isUnderFactoryTest*/,
@@ -488,7 +488,7 @@
// Need to call hideAsFinal to cache derived fields. This is normally done in PMS, but not
// in this cut down flow used for the test.
- ((ParsedPackage) result.pkgSetting.pkg).hideAsFinal();
+ ((ParsedPackage) result.mPkgSetting.pkg).hideAsFinal();
return result;
}
@@ -529,10 +529,10 @@
}
private static void assertBasicPackageScanResult(
- PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
- assertThat(scanResult.success, is(true));
+ ScanResult scanResult, String packageName, boolean isInstant) {
+ assertThat(scanResult.mSuccess, is(true));
- final PackageSetting pkgSetting = scanResult.pkgSetting;
+ final PackageSetting pkgSetting = scanResult.mPkgSetting;
assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
@@ -540,35 +540,35 @@
assertBasicApplicationInfo(scanResult, applicationInfo);
}
- private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+ private static void assertBasicPackageSetting(ScanResult scanResult,
String packageName, boolean isInstant, PackageSetting pkgSetting) {
assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
assertThat(pkgSetting.getInstantApp(0), is(isInstant));
assertThat(pkgSetting.usesStaticLibraries,
arrayContaining("some.static.library", "some.other.static.library"));
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
- assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
+ assertThat(pkgSetting.pkg, is(scanResult.mRequest.mParsedPackage));
assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName))));
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
}
- private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+ private static void assertBasicApplicationInfo(ScanResult scanResult,
ApplicationInfo applicationInfo) {
assertThat(applicationInfo.processName,
- is(scanResult.request.parsedPackage.getPackageName()));
+ is(scanResult.mRequest.mParsedPackage.getPackageName()));
final int uid = applicationInfo.uid;
assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
- scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
+ scanResult.mRequest.mParsedPackage.getPackageName()).getAbsolutePath();
assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
}
- private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
- PackageSetting pkgSetting = scanResult.pkgSetting;
+ private static void assertAbiAndPathssDerived(ScanResult scanResult) {
+ PackageSetting pkgSetting = scanResult.mPkgSetting;
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
@@ -581,8 +581,8 @@
assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
}
- private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
- PackageSetting pkgSetting = scanResult.pkgSetting;
+ private static void assertPathsNotDerived(ScanResult scanResult) {
+ PackageSetting pkgSetting = scanResult.mPkgSetting;
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index cd98d44..f1acc66 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -81,7 +81,7 @@
/* letsPersonalDataIntoProfile= */false).build());
final UserTypeDetails type = new UserTypeDetails.Builder()
.setName("a.name")
- .setEnabled(true)
+ .setEnabled(1)
.setMaxAllowed(21)
.setBaseType(FLAG_PROFILE)
.setDefaultUserInfoPropertyFlags(FLAG_EPHEMERAL)
@@ -316,6 +316,7 @@
builders.put(userTypeFull, new UserTypeDetails.Builder()
.setName(userTypeFull)
.setBaseType(FLAG_FULL)
+ .setEnabled(0)
.setDefaultRestrictions(restrictions));
final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
@@ -323,6 +324,7 @@
UserTypeDetails details = builders.get(userTypeFull).createUserTypeDetails();
assertEquals(UNLIMITED_NUMBER_OF_USERS, details.getMaxAllowedPerParent());
+ assertFalse(details.isEnabled());
assertTrue(UserRestrictionsUtils.areEqual(
makeRestrictionsBundle("no_remove_user", "no_bluetooth"),
details.getDefaultRestrictions()));
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/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 581ff54..b7eddb3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -29,6 +29,7 @@
import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
import android.content.pm.ServiceInfo
+import android.content.pm.parsing.ParsingPackageUtils
import android.os.Bundle
import android.os.Debug
import android.os.Environment
@@ -109,7 +110,7 @@
apks.mapNotNull {
try {
packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) to
- packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR,
+ packageParser2.parsePackage(it, ParsingPackageUtils.PARSE_IS_SYSTEM_DIR,
false)
} catch (ignored: Exception) {
// It is intentional that a failure of either call here will result in failing
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/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index 5012ca9..6e3f754 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -210,7 +210,7 @@
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- FaceDownDetector faceDownDetector) {
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
return mNotifierMock;
}
@@ -298,6 +298,7 @@
BatteryStats.SERVICE_NAME)),
mInjector.createSuspendBlocker(mService, "testBlocker"),
null,
+ null,
null);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index b431614..e84e365 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -215,7 +215,7 @@
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- FaceDownDetector faceDownDetector) {
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
return mNotifierMock;
}
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/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 69f0065..25b51da 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -55,6 +55,7 @@
import android.content.Intent;
import android.content.pm.ProviderInfo;
import android.net.Uri;
+import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -356,7 +357,7 @@
final UriPermissionOwner owner = new UriPermissionOwner(mService, "primary");
final ProviderInfo cameraInfo = mContext.mPmInternal.resolveContentProvider(
- PKG_CAMERA, 0, USER_PRIMARY);
+ PKG_CAMERA, 0, USER_PRIMARY, Process.SYSTEM_UID);
// By default no social can see any camera
assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index a6307b3..3716507 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -35,6 +35,7 @@
import android.net.Uri;
import android.os.FileUtils;
import android.os.PatternMatcher;
+import android.os.Process;
import android.os.UserHandle;
import android.test.mock.MockContentResolver;
import android.test.mock.MockPackageManager;
@@ -133,27 +134,32 @@
when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_COMPLEX));
- when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId)))
+ when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId),
+ eq(Process.SYSTEM_UID)))
.thenReturn(buildCameraProvider(userId));
when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId),
eq(UserHandle.getUid(userId, UID_CAMERA))))
.thenReturn(buildCameraProvider(userId));
- when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId)))
+ when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId),
+ eq(Process.SYSTEM_UID)))
.thenReturn(buildPrivateProvider(userId));
when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId),
eq(UserHandle.getUid(userId, UID_PRIVATE))))
.thenReturn(buildPrivateProvider(userId));
- when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId)))
+ when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId),
+ eq(Process.SYSTEM_UID)))
.thenReturn(buildPublicProvider(userId));
when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId),
eq(UserHandle.getUid(userId, UID_PUBLIC))))
.thenReturn(buildPublicProvider(userId));
- when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId)))
+ when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId),
+ eq(Process.SYSTEM_UID)))
.thenReturn(buildForceProvider(userId));
when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId),
eq(UserHandle.getUid(userId, UID_FORCE))))
.thenReturn(buildForceProvider(userId));
- when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId)))
+ when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId),
+ eq(Process.SYSTEM_UID)))
.thenReturn(buildComplexProvider(userId));
when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId),
eq(UserHandle.getUid(userId, UID_COMPLEX))))
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 645fa63..9e46e1f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -93,6 +93,7 @@
import android.view.Display;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -103,7 +104,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -502,6 +502,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testBoundWidgetPackageExempt() throws Exception {
assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
assertEquals(STANDBY_BUCKET_ACTIVE,
@@ -584,6 +585,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testIsAppIdle_Charging() throws Exception {
TestParoleListener paroleListener = new TestParoleListener();
mController.addListener(paroleListener);
@@ -616,6 +618,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testIsAppIdle_Enabled() throws Exception {
setChargingState(mController, false);
TestParoleListener paroleListener = new TestParoleListener();
@@ -715,6 +718,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testBuckets() throws Exception {
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
@@ -747,6 +751,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSetAppStandbyBucket() throws Exception {
// For a known package, standby bucket should be set properly
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
@@ -766,6 +771,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
// On package install, standby bucket should be ACTIVE
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
@@ -784,6 +790,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testScreenTimeAndBuckets() throws Exception {
mInjector.setDisplayOn(false);
@@ -807,6 +814,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testForcedIdle() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
@@ -819,6 +827,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testNotificationEvent() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
@@ -832,6 +841,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSlicePinnedEvent() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
@@ -845,6 +855,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSlicePinnedPrivEvent() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -852,6 +863,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionTimedOut() throws Exception {
// Set it to timeout or usage, so that prediction can override it
mInjector.mElapsedRealtime = HOUR_MS;
@@ -882,6 +894,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testOverrides() throws Exception {
// Can force to NEVER
mInjector.mElapsedRealtime = HOUR_MS;
@@ -992,6 +1005,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1015,6 +1029,7 @@
/** Test that timeouts still work properly even if invalid configuration values are set. */
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeout_InvalidThresholds() throws Exception {
mInjector.mSettingsBuilder
.setLong("screen_threshold_active", -1)
@@ -1052,6 +1067,7 @@
* timeout has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testTimeoutBeforeRestricted() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1078,6 +1094,7 @@
* Test that an app is put into the RESTRICTED bucket after enough time has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedDelay() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1100,6 +1117,7 @@
* Test that an app is put into the RESTRICTED bucket after enough time has passed.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedDelay_DelayChange() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1124,6 +1142,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1160,6 +1179,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1187,6 +1207,7 @@
* interaction.
*/
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemInteractionOverridesRestrictedTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1213,6 +1234,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedBucketDisabled() throws Exception {
mInjector.mIsRestrictedBucketEnabled = false;
// Get the controller to read the new value. Capturing the ContentObserver isn't possible
@@ -1238,6 +1260,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictedBucket_EnabledToDisabled() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
@@ -1255,6 +1278,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1272,6 +1296,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1289,6 +1314,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testCascadingTimeouts() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1312,6 +1338,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testOverlappingTimeouts() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1343,6 +1370,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemInteractionTimeout() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
// Fast forward to RARE
@@ -1366,6 +1394,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testInitialForegroundServiceTimeout() throws Exception {
mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
// Make sure app is in NEVER bucket
@@ -1399,6 +1428,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionNotOverridden() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1424,8 +1454,8 @@
assertBucket(STANDBY_BUCKET_ACTIVE);
}
- @Ignore
@Test
+ @FlakyTest(bugId = 185169504)
public void testPredictionStrikesBack() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1451,6 +1481,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_NotAddedForUserForce() throws Exception {
final int expectedReason = REASON_MAIN_FORCED_BY_USER;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
@@ -1465,6 +1496,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_AddedForSystemForce() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1487,6 +1519,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testSystemForcedFlags_SystemForceChangesBuckets() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1524,6 +1557,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testRestrictApp_MainReason() throws Exception {
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_DEFAULT);
@@ -1598,6 +1632,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testUserInteraction_CrossProfile() throws Exception {
mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
@@ -1621,6 +1656,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testUnexemptedSyncScheduled() throws Exception {
rearmLatch(PACKAGE_1);
mController.addListener(mListener);
@@ -1642,6 +1678,7 @@
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testExemptedSyncScheduled() throws Exception {
setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
mInjector.mDeviceIdleMode = true;
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 e367579..2c35860 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1854,7 +1854,7 @@
doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
any() /* window */, any() /* attrs */,
anyInt() /* viewVisibility */, anyInt() /* displayId */,
- any() /* requestedVisibility */, any() /* outInputChannel */,
+ any() /* requestedVisibilities */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
mAtm.mWindowManager.mStartingSurfaceController
.createTaskSnapshotSurface(activity, snapshot);
@@ -2600,7 +2600,7 @@
// Make mVisibleSetFromTransferredStartingWindow true.
final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
task.startActivityLocked(middle, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* newTask */, false /* isTaskSwitch */, null /* options */,
null /* sourceRecord */);
middle.makeFinishingLocked();
@@ -2613,7 +2613,7 @@
top.setVisible(false);
// The finishing middle should be able to transfer starting window to top.
task.startActivityLocked(top, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* newTask */, false /* isTaskSwitch */, null /* options */,
null /* sourceRecord */);
assertNull(middle.mStartingWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2df9a8d..1b4d0a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -32,6 +32,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
@@ -755,12 +756,12 @@
}
/**
- * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
- * move the existing task to front if the current focused stack doesn't have running task.
+ * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will
+ * move the existing task to front if the current focused root task doesn't have running task.
*/
@Test
- public void testBringTaskToFrontWhenFocusedStackIsFinising() {
- // Put 2 tasks in the same stack (simulate the behavior of home stack).
+ public void testBringTaskToFrontWhenFocusedTaskIsFinishing() {
+ // Put 2 tasks in the same root task (simulate the behavior of home root task).
final Task rootTask = new TaskBuilder(mSupervisor).build();
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setParentTask(rootTask)
@@ -777,13 +778,16 @@
assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
finishingTopActivity.finishing = true;
- // Launch the bottom task of the target stack.
+ // Launch the bottom task of the target root task.
prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
- .setReason("testBringTaskToFrontWhenTopStackIsFinising")
- .setIntent(activity.intent)
+ .setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing")
+ .setIntent(activity.intent.addFlags(
+ FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
.execute();
+ verify(activity.getRootTask()).startActivityLocked(any(), any(), anyBoolean(),
+ eq(true) /* isTaskSwitch */, any(), any());
// The hierarchies of the activity should move to front.
- assertEquals(activity, mRootWindowContainer.topRunningActivity());
+ assertEquals(activity.getTask(), mRootWindowContainer.topRunningActivity().getTask());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index a0b5fed..597ad24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -42,6 +42,7 @@
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -49,6 +50,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -65,6 +67,7 @@
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.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
@@ -105,9 +108,12 @@
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.metrics.LogMaker;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -120,6 +126,7 @@
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -139,6 +146,8 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.Arrays;
@@ -870,19 +879,6 @@
.setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
}
- @UseTestDisplay
- @Test
- public void testClearLastFocusWhenReparentingFocusedWindow() {
- final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
- final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
- defaultDisplay, "window");
- defaultDisplay.mLastFocus = window;
- mDisplayContent.mCurrentFocus = window;
- mDisplayContent.reParentWindowToken(window.mToken);
-
- assertNull(defaultDisplay.mLastFocus);
- }
-
@Test
public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
final DisplayContent portraitDisplay = createNewDisplay();
@@ -1217,10 +1213,10 @@
win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
win.getAttrs().insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- win.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, false);
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ win.setRequestedVisibilities(requestedVisibilities);
win.mActivityRecord.mTargetSdk = P;
performLayout(dc);
@@ -1748,6 +1744,31 @@
}
@Test
+ public void testFindScrollCaptureTargetWindow_secure() {
+ DisplayContent display = createNewDisplay();
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
+ secureWindow.mAttrs.flags |= FLAG_SECURE;
+
+ WindowState result = display.findScrollCaptureTargetWindow(null,
+ ActivityTaskManager.INVALID_TASK_ID);
+ assertNull(result);
+ }
+
+ @Test
+ public void testFindScrollCaptureTargetWindow_secureTaskId() {
+ DisplayContent display = createNewDisplay();
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
+ secureWindow.mAttrs.flags |= FLAG_SECURE;
+
+ WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId);
+ assertNull(result);
+ }
+
+ @Test
public void testFindScrollCaptureTargetWindow_taskId() {
DisplayContent display = createNewDisplay();
Task rootTask = createTask(display);
@@ -2177,6 +2198,138 @@
assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow());
}
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() {
+ final WindowState imeMenuDialog =
+ createWindow(mImeWindow, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog");
+ makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow);
+ assertTrue(imeMenuDialog.canReceiveKeys());
+ mDisplayContent.setInputMethodWindowLocked(mImeWindow);
+
+ // Verify imeMenuDialog can be focused window if the next IME target requests IME visible.
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+ mDisplayContent.setImeLayeringTarget(imeAppTarget);
+ spyOn(imeAppTarget);
+ doReturn(true).when(imeAppTarget).getRequestedVisibility(ITYPE_IME);
+ assertEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
+
+ // Verify imeMenuDialog doesn't be focused window if the next IME target does not
+ // request IME visible.
+ final WindowState nextImeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
+ mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
+ assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
+ }
+
+ @Test
+ public void testVirtualDisplayContent() {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SurfaceControl.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // mirror.
+ final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+ // GIVEN SurfaceControl can successfully mirror the provided surface.
+ Point surfaceSize = new Point(
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+ surfaceControlMirrors(surfaceSize);
+
+ // WHEN creating the DisplayContent for a new virtual display.
+ final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+ mDisplayInfo).build();
+
+ // THEN mirroring is initiated for the default display's DisplayArea.
+ assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testVirtualDisplayContent_capturedAreaResized() {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SurfaceControl.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // mirror.
+ final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+ // GIVEN SurfaceControl can successfully mirror the provided surface.
+ Point surfaceSize = new Point(
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+ SurfaceControl mirroredSurface = surfaceControlMirrors(surfaceSize);
+
+ // WHEN creating the DisplayContent for a new virtual display.
+ final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+ mDisplayInfo).build();
+
+ // THEN mirroring is initiated for the default display's DisplayArea.
+ assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+ float xScale = 0.7f;
+ float yScale = 2f;
+ Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
+ Math.round(surfaceSize.y * yScale));
+ virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds);
+
+ // THEN content in the captured DisplayArea is scaled to fit the surface size.
+ verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
+ 1.0f / yScale);
+ // THEN captured content is positioned in the centre of the output surface.
+ float scaledWidth = displayAreaBounds.width() / xScale;
+ float xInset = (surfaceSize.x - scaledWidth) / 2;
+ verify(mTransaction, atLeastOnce()).setPosition(mirroredSurface, xInset, 0);
+
+ mockSession.finishMocking();
+ }
+
+ private class TestToken extends Binder {
+ }
+
+ /**
+ * Creates a WindowToken associated with the default task DisplayArea, in order for that
+ * DisplayArea to be mirrored.
+ */
+ private IBinder setUpDefaultTaskDisplayAreaWindowToken() {
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // mirror.
+ final IBinder tokenToMirror = new TestToken();
+ doReturn(tokenToMirror).when(mWm.mDisplayManagerInternal).getWindowTokenClientToMirror(
+ anyInt());
+
+ // GIVEN the default task display area is represented by the WindowToken.
+ spyOn(mWm.mWindowContextListenerController);
+ doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when(
+ mWm.mWindowContextListenerController).getContainer(any());
+ return tokenToMirror;
+ }
+
+ /**
+ * SurfaceControl successfully creates a mirrored surface of the given size.
+ */
+ private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
+ // Do not set the parent, since the mirrored surface is the root of a new surface hierarchy.
+ SurfaceControl mirroredSurface = new SurfaceControl.Builder()
+ .setName("mirroredSurface")
+ .setBufferSize(surfaceSize.x, surfaceSize.y)
+ .setCallsite("mirrorSurface")
+ .build();
+ doReturn(mirroredSurface).when(() -> SurfaceControl.mirrorSurface(any()));
+ doReturn(surfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
+ anyInt());
+ return mirroredSurface;
+ }
+
private void removeRootTaskTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 3741d49..4957ab9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -65,6 +65,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
@@ -114,7 +115,7 @@
spyOn(mNavBarWindow);
// Disabling this call for most tests since it can override the systemUiFlags when called.
- doReturn(false).when(mDisplayPolicy).updateSystemUiVisibilityLw();
+ doNothing().when(mDisplayPolicy).updateSystemBarAttributes();
updateDisplayFrames();
}
@@ -478,9 +479,9 @@
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mDisplayContent.getInsetsStateController().getRawInsetsState()
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- mWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ mWindow.setRequestedVisibilities(requestedVisibilities);
addWindowWithRawInsetsState(mWindow);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -498,9 +499,9 @@
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mDisplayContent.getInsetsStateController().getRawInsetsState()
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- mWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ mWindow.setRequestedVisibilities(requestedVisibilities);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindowWithRawInsetsState(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 5b04c91..07d467b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -49,6 +49,7 @@
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -181,9 +182,9 @@
// Add a fullscreen (MATCH_PARENT x MATCH_PARENT) app window which hides status bar.
final WindowState fullscreenApp = addWindow(TYPE_APPLICATION, "fullscreenApp");
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- fullscreenApp.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ fullscreenApp.setRequestedVisibilities(requestedVisibilities);
// Add a non-fullscreen dialog window.
final WindowState dialog = addWindow(TYPE_APPLICATION, "dialog");
@@ -216,9 +217,9 @@
// Assume mFocusedWindow is updated but mTopFullscreenOpaqueWindowState hasn't.
final WindowState newFocusedFullscreenApp = addWindow(TYPE_APPLICATION, "newFullscreenApp");
- final InsetsState newRequestedState = new InsetsState();
- newRequestedState.getSource(ITYPE_STATUS_BAR).setVisible(true);
- newFocusedFullscreenApp.updateRequestedVisibility(newRequestedState);
+ final InsetsVisibilities newRequestedVisibilities = new InsetsVisibilities();
+ newRequestedVisibilities.setVisibility(ITYPE_STATUS_BAR, true);
+ newFocusedFullscreenApp.setRequestedVisibilities(newRequestedVisibilities);
// Make sure status bar is hidden by previous insets state.
mDisplayContent.getInsetsPolicy().updateBarControlTarget(fullscreenApp);
@@ -279,10 +280,10 @@
doNothing().when(policy).startAnimation(anyBoolean(), any());
// Make both system bars invisible.
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
- requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
- mAppWindow.updateRequestedVisibility(requestedState);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, false);
+ mAppWindow.setRequestedVisibilities(requestedVisibilities);
policy.updateBarControlTarget(mAppWindow);
waitUntilWindowAnimatorIdle();
assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState()
@@ -373,7 +374,10 @@
assertTrue(state.getSource(ITYPE_STATUS_BAR).isVisible());
assertTrue(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
- mAppWindow.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, true);
+ requestedVisibilities.setVisibility(ITYPE_NAVIGATION_BAR, true);
+ mAppWindow.setRequestedVisibilities(requestedVisibilities);
policy.onInsetsModified(mAppWindow);
waitUntilWindowAnimatorIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index c483ae9..2987f94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -31,7 +31,7 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
-import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -203,9 +203,9 @@
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
- InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- target.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ target.setRequestedVisibilities(requestedVisibilities);
mProvider.updateClientVisibility(target);
assertFalse(mSource.isVisible());
}
@@ -216,9 +216,9 @@
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
- InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- target.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ target.setRequestedVisibilities(requestedVisibilities);
mProvider.updateClientVisibility(target);
assertTrue(mSource.isVisible());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 80961d7..f8c84df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -48,6 +48,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
@@ -174,10 +175,10 @@
mImeWindow.setHasSurface(true);
getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
getController().onImeControlTargetChanged(mDisplayContent.getImeTarget(IME_TARGET_INPUT));
- final InsetsState requestedState = new InsetsState();
- requestedState.getSource(ITYPE_IME).setVisible(true);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_IME, true);
mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow()
- .updateRequestedVisibility(requestedState);
+ .setRequestedVisibilities(requestedVisibilities);
getController().onInsetsModified(mDisplayContent.getImeTarget(IME_TARGET_INPUT));
// Send our spy window (app) into the system so that we can detect the invocation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 5af68021..e3c38b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -859,6 +859,40 @@
}
@Test
+ public void testFreezeTaskListOrder_replaceTask() {
+ // Create two tasks with the same affinity
+ Task affinityTask1 = createTaskBuilder(".AffinityTask1")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .build();
+ Task affinityTask2 = createTaskBuilder(".AffinityTask2")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .build();
+ affinityTask2.affinity = affinityTask1.affinity = "affinity";
+
+ // Add some tasks
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(affinityTask1);
+ mRecentTasks.add(mTasks.get(1));
+ mCallbacksRecorder.clear();
+
+ // Freeze the list
+ mRecentTasks.setFreezeTaskListReordering();
+ assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Add the affinity task
+ mRecentTasks.add(affinityTask2);
+
+ assertRecentTasksOrder(mTasks.get(1),
+ affinityTask2,
+ mTasks.get(0));
+
+ assertThat(mCallbacksRecorder.mAdded).hasSize(1);
+ assertThat(mCallbacksRecorder.mAdded).contains(affinityTask2);
+ assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
+ assertThat(mCallbacksRecorder.mRemoved).contains(affinityTask1);
+ }
+
+ @Test
public void testFreezeTaskListOrder_timeout() {
// Add some tasks
mRecentTasks.add(mTasks.get(0));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 5989497..d10c006 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -320,6 +320,11 @@
assertScaled();
// Activity is sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
+
+ final WindowState appWindow = addWindowToActivity(mActivity);
+ assertTrue(mActivity.hasSizeCompatBounds());
+ assertEquals("App window must use size compat bounds for layout in screen space",
+ mActivity.getBounds(), appWindow.getBounds());
}
@Test
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..c35f317 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;
@@ -44,6 +41,7 @@
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizerToken;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
@@ -65,6 +63,7 @@
private TaskFragmentOrganizerController mController;
private TaskFragmentOrganizer mOrganizer;
+ private TaskFragmentOrganizerToken mOrganizerToken;
private ITaskFragmentOrganizer mIOrganizer;
private TaskFragment mTaskFragment;
private TaskFragmentInfo mTaskFragmentInfo;
@@ -76,7 +75,8 @@
public void setup() {
mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
- mIOrganizer = mOrganizer.getIOrganizer();
+ mOrganizerToken = mOrganizer.getOrganizerToken();
+ mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
mTaskFragmentInfo = mock(TaskFragmentInfo.class);
mFragmentToken = new Binder();
mTaskFragment =
@@ -198,9 +198,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));
}
@@ -236,7 +238,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -258,7 +260,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -281,7 +283,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -307,8 +309,8 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
- taskFragment2.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -318,10 +320,13 @@
mOrganizer.applyTransaction(mTransaction);
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
- mTransaction.createTaskFragment(mock(TaskFragmentCreationParams.class));
+ final TaskFragmentCreationParams mockParams = mock(TaskFragmentCreationParams.class);
+ doReturn(mOrganizerToken).when(mockParams).getOrganizer();
+ mTransaction.createTaskFragment(mockParams);
mTransaction.startActivityInTaskFragment(
- mFragmentToken, new Intent(), null /* activityOptions */);
+ mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
+ mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class));
// It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
// testing the security check here.
@@ -352,7 +357,7 @@
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index ce2d748..0d919d109 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -20,6 +20,7 @@
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -153,6 +154,7 @@
if (mSystemDecorations) {
doReturn(true).when(newDisplay).supportsSystemDecorations();
doReturn(true).when(displayPolicy).hasNavigationBar();
+ doReturn(20).when(displayPolicy).getNavigationBarHeight(anyInt(), anyInt());
} else {
doReturn(false).when(displayPolicy).hasNavigationBar();
doReturn(false).when(displayPolicy).hasStatusBar();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index efe6538..316309c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -35,6 +35,7 @@
import android.view.Gravity;
import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
@@ -276,7 +277,9 @@
imeFrame.top = 400;
imeSource.setFrame(imeFrame);
imeSource.setVisible(true);
- w.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_IME, true);
+ w.setRequestedVisibilities(requestedVisibilities);
w.mAboveInsetsState.addSource(imeSource);
// With no insets or system decor all the frames incoming from PhoneWindowManager
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 83cdc3ba..a91298f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -56,6 +56,7 @@
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.View;
import android.view.WindowManager;
@@ -278,7 +279,7 @@
.getWindowType(eq(windowContextToken));
mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY,
- UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(),
+ UserHandle.USER_SYSTEM, new InsetsVisibilities(), null, new InsetsState(),
new InsetsSourceControl[0]);
verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 3929082..aa56183 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -88,6 +88,7 @@
import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.InsetsVisibilities;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -440,9 +441,9 @@
.setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */);
mDisplayContent.getInsetsStateController().onBarControlTargetChanged(
app, null /* fakeTopControlling */, app, null /* fakeNavControlling */);
- final InsetsState state = new InsetsState();
- state.getSource(ITYPE_STATUS_BAR).setVisible(false);
- app.updateRequestedVisibility(state);
+ final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
+ requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
+ app.setRequestedVisibilities(requestedVisibilities);
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
.updateClientVisibility(app);
waitUntilHandlersIdle();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index e408cfc..965f126 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -87,14 +87,14 @@
*/
final class HotwordDetectionConnection {
private static final String TAG = "HotwordDetectionConnection";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
// TODO: These constants need to be refined.
private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
+ private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
// TODO: This may need to be a Handler(looper)
@@ -103,6 +103,7 @@
private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
+ private final IHotwordRecognitionStatusCallback mCallback;
final Object mLock;
final int mVoiceInteractionServiceUid;
@@ -110,11 +111,11 @@
final int mUser;
final Context mContext;
volatile HotwordDetectionServiceIdentity mIdentity;
- private IHotwordRecognitionStatusCallback mCallback;
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
private ScheduledFuture<?> mCancellationTaskFuture;
+ private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
/** Identity used for attributing app ops when delivering data to the Interactor. */
@GuardedBy("mLock")
@@ -128,17 +129,24 @@
private boolean mPerformingSoftwareHotwordDetection;
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
private IBinder mAudioFlinger;
+ private boolean mDebugHotwordLogging = false;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
+ @Nullable SharedMemory sharedMemory,
+ @NonNull IHotwordRecognitionStatusCallback callback) {
+ if (callback == null) {
+ Slog.w(TAG, "Callback is null while creating connection");
+ throw new IllegalArgumentException("Callback is null while creating connection");
+ }
mLock = lock;
mContext = context;
mVoiceInteractionServiceUid = voiceInteractionServiceUid;
mVoiceInteractorIdentity = voiceInteractorIdentity;
mDetectionComponentName = serviceName;
mUser = userId;
+ mCallback = callback;
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
intent.setComponent(mDetectionComponentName);
initAudioFlingerLocked();
@@ -147,22 +155,13 @@
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
- if (callback == null) {
- updateStateLocked(options, sharedMemory);
- return;
- }
- mCallback = callback;
-
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
// TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
// until the current session is closed.
mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
- if (DEBUG) {
- Slog.i(TAG, "Time to restart the process, TTL has passed");
- }
-
+ Slog.v(TAG, "Time to restart the process, TTL has passed");
synchronized (mLock) {
restartProcessLocked();
}
@@ -268,9 +267,9 @@
}
void cancelLocked() {
- if (DEBUG) {
- Slog.d(TAG, "cancelLocked");
- }
+ Slog.v(TAG, "cancelLocked");
+ clearDebugHotwordLoggingTimeoutLocked();
+ mDebugHotwordLogging = false;
if (mRemoteHotwordDetectionService.isBound()) {
mRemoteHotwordDetectionService.unbind();
LocalServices.getService(PermissionManagerServiceInternal.class)
@@ -288,6 +287,7 @@
// TODO(b/191742511): this logic needs a test
if (!mUpdateStateAfterStartFinished.get()
&& Instant.now().minus(MAX_UPDATE_TIMEOUT_DURATION).isBefore(mLastRestartInstant)) {
+ Slog.v(TAG, "call updateStateAfterProcessStart");
updateStateAfterProcessStart(options, sharedMemory);
} else {
mRemoteHotwordDetectionService.run(
@@ -330,6 +330,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
} else {
Slog.i(TAG, "Hotword detection has already completed");
@@ -407,15 +410,11 @@
private void detectFromDspSourceForTest(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
IHotwordRecognitionStatusCallback externalCallback) {
- if (DEBUG) {
- Slog.d(TAG, "detectFromDspSourceForTest");
- }
+ Slog.v(TAG, "detectFromDspSourceForTest");
IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
@Override
public void onDetected(HotwordDetectedResult result) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onDetected");
- }
+ Slog.v(TAG, "onDetected");
synchronized (mLock) {
if (mValidatingDspTrigger) {
mValidatingDspTrigger = false;
@@ -424,6 +423,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
} else {
Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
@@ -433,13 +435,14 @@
@Override
public void onRejected(HotwordRejectedResult result) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onRejected");
- }
+ Slog.v(TAG, "onRejected");
synchronized (mLock) {
if (mValidatingDspTrigger) {
mValidatingDspTrigger = false;
externalCallback.onRejected(result);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
} else {
Slog.i(TAG, "Ignored hotword rejected since trigger has been handled");
}
@@ -482,6 +485,9 @@
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
+ " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + result);
+ }
}
}
}
@@ -498,6 +504,9 @@
}
mValidatingDspTrigger = false;
externalCallback.onRejected(result);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
}
}
};
@@ -514,19 +523,37 @@
}
void forceRestart() {
- if (DEBUG) {
- Slog.i(TAG, "Requested to restart the service internally. Performing the restart");
- }
+ Slog.v(TAG, "Requested to restart the service internally. Performing the restart");
synchronized (mLock) {
restartProcessLocked();
}
}
- private void restartProcessLocked() {
- if (DEBUG) {
- Slog.i(TAG, "Restarting hotword detection process");
- }
+ void setDebugHotwordLoggingLocked(boolean logging) {
+ Slog.v(TAG, "setDebugHotwordLoggingLocked: " + logging);
+ clearDebugHotwordLoggingTimeoutLocked();
+ mDebugHotwordLogging = logging;
+ if (logging) {
+ // Reset mDebugHotwordLogging to false after one hour
+ mDebugHotwordLoggingTimeoutFuture = mScheduledExecutorService.schedule(() -> {
+ Slog.v(TAG, "Timeout to reset mDebugHotwordLogging to false");
+ synchronized (mLock) {
+ mDebugHotwordLogging = false;
+ }
+ }, RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ private void clearDebugHotwordLoggingTimeoutLocked() {
+ if (mDebugHotwordLoggingTimeoutFuture != null) {
+ mDebugHotwordLoggingTimeoutFuture.cancel(/* mayInterruptIfRunning= */true);
+ mDebugHotwordLoggingTimeoutFuture = null;
+ }
+ }
+
+ private void restartProcessLocked() {
+ Slog.v(TAG, "Restarting hotword detection process");
ServiceConnection oldConnection = mRemoteHotwordDetectionService;
// TODO(volnov): this can be done after connect() has been successful.
@@ -547,9 +574,7 @@
// Recreate connection to reset the cache.
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
- if (DEBUG) {
- Slog.i(TAG, "Started the new process, issuing #onProcessRestarted");
- }
+ Slog.v(TAG, "Started the new process, issuing #onProcessRestarted");
try {
mCallback.onProcessRestarted();
} catch (RemoteException e) {
@@ -700,6 +725,9 @@
bestEffortClose(serviceAudioSource);
bestEffortClose(audioSource);
+ if (mDebugHotwordLogging && result != null) {
+ Slog.i(TAG, "Egressed rejected result: " + result);
+ }
// TODO: Propagate the HotwordRejectedResult.
}
@@ -714,6 +742,9 @@
if (triggerResult != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(
triggerResult) + " bits from hotword trusted process");
+ if (mDebugHotwordLogging) {
+ Slog.i(TAG, "Egressed detected result: " + triggerResult);
+ }
}
// TODO: Add a delay before closing.
bestEffortClose(audioSource);
@@ -773,9 +804,7 @@
}
synchronized (mLock) {
if (!mRespectServiceConnectionStatusChanged) {
- if (DEBUG) {
- Slog.d(TAG, "Ignored onServiceConnectionStatusChanged event");
- }
+ Slog.v(TAG, "Ignored onServiceConnectionStatusChanged event");
return;
}
mIsBound = connected;
@@ -792,9 +821,7 @@
super.binderDied();
synchronized (mLock) {
if (!mRespectServiceConnectionStatusChanged) {
- if (DEBUG) {
- Slog.d(TAG, "Ignored #binderDied event");
- }
+ Slog.v(TAG, "Ignored #binderDied event");
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
index b9e1fcd..68b2e61 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
@@ -29,7 +29,6 @@
import android.media.permission.PermissionUtil;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceSpecificException;
import android.text.TextUtils;
import android.util.Slog;
@@ -117,8 +116,8 @@
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
- * permission, or a {@link ServiceSpecificException} with a {@link
- * #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.
@@ -130,15 +129,12 @@
permission);
switch (status) {
case PermissionChecker.PERMISSION_GRANTED:
+ case PermissionChecker.PERMISSION_SOFT_DENIED:
return;
case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException(
TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
permission, toString(identity)));
- case PermissionChecker.PERMISSION_SOFT_DENIED:
- throw new ServiceSpecificException(TEMPORARY_PERMISSION_DENIED,
- TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
- permission, toString(identity)));
default:
throw new RuntimeException("Unexpected permission check result.");
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ccf4267..71541ad 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -832,6 +832,17 @@
mImpl.forceRestartHotwordDetector();
}
+ // Called by Shell command
+ void setDebugHotwordLogging(boolean logging) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "setTemporaryLogging without running voice interaction service");
+ return;
+ }
+ mImpl.setDebugHotwordLoggingLocked(logging);
+ }
+ }
+
@Override
public void showSession(Bundle args, int flags) {
synchronized (this) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index cbcbf52..558a9ac 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -79,8 +79,7 @@
class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
final static String TAG = "VoiceInteractionServiceManager";
- // TODO (b/177502877): Set the Debug flag to false before shipping.
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
final static String CLOSE_REASON_VOICE_INTERACTION = "voiceinteraction";
@@ -420,9 +419,7 @@
@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory,
IHotwordRecognitionStatusCallback callback) {
- if (DEBUG) {
- Slog.d(TAG, "updateStateLocked");
- }
+ Slog.v(TAG, "updateStateLocked");
if (mHotwordDetectionComponentName == null) {
Slog.w(TAG, "Hotword detection service name not found");
throw new IllegalStateException("Hotword detection service name not found");
@@ -584,6 +581,14 @@
mHotwordDetectionConnection.forceRestart();
}
+ void setDebugHotwordLoggingLocked(boolean logging) {
+ if (mHotwordDetectionConnection == null) {
+ Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active");
+ return;
+ }
+ mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging);
+ }
+
void resetHotwordDetectionConnectionLocked() {
if (DEBUG) {
Slog.d(TAG, "resetHotwordDetectionConnectionLocked");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
index cdd8f7b..9bdf4e4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -56,6 +56,8 @@
return requestDisable(pw);
case "restart-detection":
return requestRestartDetection(pw);
+ case "set-debug-hotword-logging":
+ return setDebugHotwordLogging(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -76,9 +78,14 @@
pw.println("");
pw.println(" disable [true|false]");
pw.println(" Temporarily disable (when true) service");
+ pw.println("");
pw.println(" restart-detection");
pw.println(" Force a restart of a hotword detection service");
pw.println("");
+ pw.println(" set-debug-hotword-logging [true|false]");
+ pw.println(" Temporarily enable or disable debug logging for hotword result.");
+ pw.println(" The debug logging will be reset after one hour from last enable.");
+ pw.println("");
}
}
@@ -157,6 +164,17 @@
return 0;
}
+ private int setDebugHotwordLogging(PrintWriter pw) {
+ boolean logging = Boolean.parseBoolean(getNextArgRequired());
+ Slog.i(TAG, "setDebugHotwordLogging(): " + logging);
+ try {
+ mService.setDebugHotwordLogging(logging);
+ } catch (Exception e) {
+ return handleError(pw, "setDebugHotwordLogging()", e);
+ }
+ return 0;
+ }
+
private static int handleError(PrintWriter pw, String message, Exception e) {
Slog.e(TAG, "error calling " + message, e);
pw.printf("Error calling %s: %s\n", message, e);
diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp
index 201ab53..1cacc03 100644
--- a/telephony/common/Android.bp
+++ b/telephony/common/Android.bp
@@ -19,6 +19,14 @@
],
}
+filegroup {
+ name: "framework-mms-shared-srcs",
+ visibility: ["//packages/apps/Bluetooth"],
+ srcs: [
+ "com/google/android/mms/**/*.java",
+ ],
+}
+
genrule {
name: "statslog-telephony-common-java-gen",
tools: ["stats-log-api-gen"],
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 6b82045..b5d97ab 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -567,6 +567,10 @@
*/
public static int getFrequencyFromNrArfcn(int nrArfcn) {
+ if (nrArfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int globalKhz = 0;
int rangeOffset = 0;
int arfcnOffset = 0;
@@ -632,6 +636,10 @@
*/
public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) {
+ if (uarfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int offsetKhz = 0;
for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants.
UtranBandArfcnFrequency.values()) {
@@ -702,6 +710,10 @@
*/
public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) {
+ if (arfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int uplinkFrequencyFirst = 0;
int arfcnOffset = 0;
int downlinkOffset = 0;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 09e19d2..0e4c44e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -490,6 +490,12 @@
/** Used in Cellular Network Settings for preferred network type. */
public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+ /**
+ * Used in Cellular Network Settings for preferred network type to show 4G only mode.
+ * @hide
+ */
+ public static final String KEY_4G_ONLY_BOOL = "4g_only_bool";
+
/** Show cdma network mode choices 1x, 3G, global etc. */
public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
@@ -3538,7 +3544,7 @@
"nr_advanced_capable_pco_id_int";
/**
- * This configuration allows the framework to use user data communication to detect RRC state,
+ * This configuration allows the framework to use user data communication to detect Idle state,
* and this is used on the 5G icon.
*
* There is a new way for for RRC state detection at Android 12. If
@@ -3546,16 +3552,23 @@
* {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true,
* then framework can use PHYSICAL_CHANNEL_CONFIG for RRC state detection. Based on this
* condition, some carriers want to use the legacy behavior that way is using user data
- * communication to detect the RRC state. Therefore, this configuration allows the framework
- * to use user data communication to detect RRC state.
+ * communication to detect the Idle state. Therefore, this configuration allows the framework
+ * to use user data communication to detect Idle state.
*
- * The precondition is
+ * There are 3 situations reflects the carrier define Idle state.
+ * 1. using PHYSICAL_CHANNEL_CONFIG to detect RRC Idle
+ * 2. using all of data connections to detect RRC Idle.
+ * 3. using data communication(consider internet data connection only) to detect data Idle.
+ *
+ * How to setup for above 3 cases?
+ * For below part, we call the condition#1 is device support
* {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}(
- * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true,
- * otherwise this config is not working.
- * If this is true, framework uses the user data communication for RRC state detection.
- * If this is false, framework uses the PHYSICAL_CHANNEL_CONFIG for RRC state detection.
+ * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}).
+ * The condition#2 is carrier enable the KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL.
*
+ * For case#1, the condition#1 is true and the condition#2 is false.
+ * For case#2, the condition#1 is false and the condition#2 is false.
+ * For case#3, the condition#2 is true.
* @hide
*/
public static final String KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL =
@@ -5250,6 +5263,7 @@
sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+ sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
sDefaults.putBoolean(KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL, false);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 72150dd..6ada32e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -178,7 +178,7 @@
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3);
mCsiCqiReport = csiCqiReport.stream()
- .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 1, 3)))
+ .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 0, 15)))
.collect(Collectors.toList());
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 8df41fb..d250088 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -338,7 +338,8 @@
private void setUplinkFrequency() {
switch (mNetworkType){
case TelephonyManager.NETWORK_TYPE_NR:
- mUplinkFrequency = mDownlinkFrequency;
+ mUplinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn(
+ mUplinkChannelNumber);
break;
case TelephonyManager.NETWORK_TYPE_LTE:
mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 2d50e08..63a7acf 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -115,9 +116,9 @@
private int mDataRoaming;
/**
- * SIM Icon bitmap
+ * SIM icon bitmap cache
*/
- private Bitmap mIconBitmap;
+ @Nullable private Bitmap mIconBitmap;
/**
* Mobile Country Code
@@ -405,6 +406,10 @@
* @return A bitmap icon for this {@code SubscriptionInfo}.
*/
public Bitmap createIconBitmap(Context context) {
+ if (mIconBitmap == null) {
+ mIconBitmap = BitmapFactory.decodeResource(context.getResources(),
+ com.android.internal.R.drawable.ic_sim_card_multi_24px_clr);
+ }
int width = mIconBitmap.getWidth();
int height = mIconBitmap.getHeight();
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
@@ -774,7 +779,6 @@
String mcc = source.readString();
String mnc = source.readString();
String countryIso = source.readString();
- Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader());
boolean isEmbedded = source.readBoolean();
UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR);
String cardString = source.readString();
@@ -793,10 +797,10 @@
boolean areUiccApplicationsEnabled = source.readBoolean();
SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
- carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
- countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
- groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
- carrierConfigAccessRules, areUiccApplicationsEnabled);
+ carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null,
+ mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, cardId,
+ isOpportunistic, groupUUID, isGroupDisabled, carrierid, profileClass, subType,
+ groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled);
info.setAssociatedPlmns(ehplmns, hplmns);
return info;
}
@@ -821,7 +825,7 @@
dest.writeString(mMcc);
dest.writeString(mMnc);
dest.writeString(mCountryIso);
- dest.writeParcelable(mIconBitmap, flags);
+ // Do not write mIconBitmap since it should be lazily loaded on first usage
dest.writeBoolean(mIsEmbedded);
dest.writeTypedArray(mNativeAccessRules, flags);
dest.writeString(mCardString);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
new file mode 100644
index 0000000..3074e28
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class NonResizeableAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
new file mode 100644
index 0000000..19fefb9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class TwoActivitiesAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+ fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
+ val button = device.wait(
+ Until.findObject(By.res(getPackage(), "launch_second_activity")),
+ FIND_TIMEOUT)
+
+ require(button != null) {
+ "Button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)"
+ }
+ button.click()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(component)
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
new file mode 100644
index 0000000..70a79d1
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the back and forward transition between 2 activities.
+ * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ testApp.openSecondActivity(device, wmHelper)
+ device.pressBack()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun finishSubActivity() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+ .then()
+ .isAppWindowOnTop(ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME)
+ .then()
+ .isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun entireScreenCovered() {
+ testSpec.entireScreenCovered(testSpec.config.startRotation)
+ }
+
+ @Postsubmit
+ @Test
+ fun launcherWindowNotVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(LAUNCHER_COMPONENT, ignoreActivity = true)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun launcherLayerNotVisible() {
+ testSpec.assertLayers { this.isInvisible(LAUNCHER_COMPONENT) }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
new file mode 100644
index 0000000..7077d3b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app while the phone is locked
+ * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val testApp = NonResizeableAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ eachRun {
+ device.sleep()
+ wmHelper.waitForAppTransitionIdle()
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() {
+ testSpec.assertLayersEnd {
+ isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun nonResizableAppLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.notContains(testApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ .then()
+ .isVisible(testApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun nonResizableAppWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.notContains(testApp.component)
+ .then()
+ .isAppWindowInvisible(testApp.component,
+ ignoreActivity = true, isOptional = true)
+ .then()
+ .isAppWindowVisible(testApp.component, ignoreActivity = true)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun nonResizableAppWindowBecomesVisibleAtEnd() {
+ testSpec.assertWmEnd {
+ this.isVisible(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+ @FlakyTest
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
+ @FlakyTest
+ @Test
+ override fun focusChanges() = super.focusChanges()
+
+ @FlakyTest
+ @Test
+ override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+ @FlakyTest
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() =
+ super.appWindowReplacesLauncherAsTopWindow()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedNavigationModes =
+ listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
+ supportedRotations = listOf(Surface.ROTATION_0)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 860a5ae..1435120 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -44,7 +44,7 @@
abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
withTestName { testSpec.name }
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 1599ed4..3b9f33a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -59,5 +59,26 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".NonResizeableActivity"
+ android:resizeableActivity="false"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
+ android:label="NonResizeableApp"
+ android:exported="true"
+ android:showOnLockScreen="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name=".ButtonActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ButtonActivity"
+ android:configChanges="orientation|screenSize"
+ android:label="ButtonActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
new file mode 100644
index 0000000..fe7bced
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_orange_light">
+ <Button
+ android:id="@+id/launch_second_activity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Second activity" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
new file mode 100644
index 0000000..6d5a9dd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/holo_orange_light">
+
+ <TextView
+ android:id="@+id/NonResizeableTest"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="NonResizeableActivity"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 0ccc498..224d2ac 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -41,4 +41,14 @@
public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".SimpleActivity");
+
+ public static final String NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME = "NonResizeableApp";
+ public static final ComponentName NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".NonResizeableActivity");
+
+ public static final String BUTTON_ACTIVITY_LAUNCHER_NAME = "ButtonApp";
+ public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ButtonActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
new file mode 100644
index 0000000..b42ac2a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class ButtonActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_button);
+
+ Button button = findViewById(R.id.launch_second_activity);
+ button.setOnClickListener(v -> {
+ Intent intent = new Intent(ButtonActivity.this, SimpleActivity.class);
+ startActivity(intent);
+ });
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
new file mode 100644
index 0000000..61019d8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+
+public class NonResizeableActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.activity_non_resizeable);
+
+ setShowWhenLocked(true);
+ setTurnScreenOn(true);
+ KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+ if (keyguardManager != null) {
+ keyguardManager.requestDismissKeyguard(this, null);
+ }
+ }
+}
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/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index dc090aa..c59a41e 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -37,10 +37,10 @@
"vts",
],
data: [
- ":NotoColorEmoji.ttf",
":NotoSerif-Regular.ttf",
":NotoSerif-Bold.ttf",
":UpdatableSystemFontTestCertDer",
+ ":UpdatableSystemFontTest_NotoColorEmoji.ttf",
":UpdatableSystemFontTest_NotoColorEmoji.sig",
":UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
":UpdatableSystemFontTest_NotoColorEmojiV0.sig",
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 5eba336..64b698d 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -22,9 +22,9 @@
}
// An existing module name is reused to avoid merge conflicts.
-// TODO: fix the font and module name.
+// TODO: fix the font file name.
filegroup {
- name: "NotoColorEmojiTtf",
+ name: "UpdatableSystemFontTest_NotoColorEmoji.ttf",
srcs: ["NotoColorEmoji.ttf"],
}
@@ -49,7 +49,7 @@
genrule {
name: "UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
- srcs: [":NotoColorEmoji.ttf"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
out: ["UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
@@ -60,7 +60,7 @@
genrule {
name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
- srcs: [":NotoColorEmoji.ttf"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
@@ -71,7 +71,7 @@
genrule {
name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
- srcs: [":NotoColorEmoji.ttf"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
@@ -96,7 +96,7 @@
genrule {
name: "UpdatableSystemFontTest_NotoColorEmoji.sig",
defaults: ["updatable_system_font_sig_gen_default"],
- srcs: [":NotoColorEmoji.ttf"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
out: ["UpdatableSystemFontTest_NotoColorEmoji.sig"],
}
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index f7a5ba1..ea886db 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -26,9 +26,8 @@
namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
-static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>({
- "Q", "R", "S", "T"
-});
+static const auto sDevelopmentSdkCodeNames =
+ std::unordered_set<StringPiece>({"Q", "R", "S", "Tiramisu"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},
diff --git a/tools/codegen/OWNERS b/tools/codegen/OWNERS
index da723b3..c9bd260 100644
--- a/tools/codegen/OWNERS
+++ b/tools/codegen/OWNERS
@@ -1 +1 @@
-eugenesusla@google.com
\ No newline at end of file
+chiuwinson@google.com
diff --git a/tools/codegen/src/com/android/codegen/ImportsProvider.kt b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
index 27dd958..46df273 100644
--- a/tools/codegen/src/com/android/codegen/ImportsProvider.kt
+++ b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
@@ -53,10 +53,25 @@
* Optionally shortens a class reference if there's a corresponding import present
*/
fun classRef(fullName: String): String {
-
val pkg = fullName.substringBeforeLast(".")
val simpleName = fullName.substringAfterLast(".")
- if (fileAst.imports.any { imprt ->
+ val imports = fileAst.imports
+
+ // If an import of the same class name is available,
+ // use it instead of the internal Android package variants.
+ if (fullName.startsWith("com.android.internal.util.")
+ && imports.any {
+ it.nameAsString.endsWith(fullName.removePrefix("com.android.internal.util."))
+ }
+ ) {
+ return fullName.removePrefix("com.android.internal.util.")
+ } else if (fullName.startsWith("android.annotation")
+ && imports.any { it.nameAsString.endsWith(simpleName) }
+ ) {
+ return simpleName
+ }
+
+ if (imports.any { imprt ->
imprt.nameAsString == fullName
|| (imprt.isAsterisk && imprt.nameAsString == pkg)
}) {
@@ -89,4 +104,4 @@
/** @see classRef */
inline fun <reified T : Any> ImportsProvider.classRef(): String {
return classRef(T::class.java.name)
-}
\ No newline at end of file
+}