Merge "[pm/incremental] unit tests for state transitions"
diff --git a/Android.bp b/Android.bp
index 5af7756..4121b8a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -598,6 +598,12 @@
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/packages/Tethering/tests/unit",
],
+ errorprone: {
+ javacflags: [
+ "-Xep:AndroidFrameworkCompatChange:ERROR",
+ "-Xep:AndroidFrameworkUid:ERROR",
+ ],
+ },
}
// This "framework" module is NOT installed to the device. It's
diff --git a/StubLibraries.bp b/StubLibraries.bp
index a3a2094..53053ce 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -58,7 +58,24 @@
"media/aidl",
],
},
- libs: ["framework-internal-utils"],
+ // These are libs from framework-internal-utils that are required (i.e. being referenced)
+ // from framework-non-updatable-sources. Add more here when there's a need.
+ // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular
+ // dependencies gets bigger.
+ libs: [
+ "android.hardware.cas-V1.2-java",
+ "android.hardware.health-V1.0-java-constants",
+ "android.hardware.radio-V1.5-java",
+ "android.hardware.thermal-V1.0-java-constants",
+ "android.hardware.thermal-V2.0-java",
+ "android.hardware.tv.input-V1.0-java-constants",
+ "android.hardware.tv.tuner-V1.0-java-constants",
+ "android.hardware.usb-V1.0-java-constants",
+ "android.hardware.usb-V1.1-java-constants",
+ "android.hardware.usb.gadget-V1.0-java",
+ "android.hardware.vibrator-V1.3-java",
+ "framework-protos",
+ ],
installable: false,
annotations_enabled: true,
previous_api: ":android.api.public.latest",
@@ -143,6 +160,11 @@
api_file: "non-updatable-api/current.txt",
removed_api_file: "non-updatable-api/removed.txt",
},
+ last_released: {
+ api_file: ":android-non-updatable.api.public.latest",
+ removed_api_file: ":android-non-updatable-removed.api.public.latest",
+ baseline_file: ":public-api-incompatibilities-with-last-released",
+ },
api_lint: {
enabled: true,
new_since: ":android-non-updatable.api.public.latest",
@@ -205,6 +227,11 @@
api_file: "non-updatable-api/system-current.txt",
removed_api_file: "non-updatable-api/system-removed.txt",
},
+ last_released: {
+ api_file: ":android-non-updatable.api.system.latest",
+ removed_api_file: ":android-non-updatable-removed.api.system.latest",
+ baseline_file: ":system-api-incompatibilities-with-last-released"
+ },
api_lint: {
enabled: true,
new_since: ":android-non-updatable.api.system.latest",
diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
index bb6b691..66b2b0e 100644
--- a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
+++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
@@ -53,19 +53,19 @@
final String text = mTextUtil.nextRandomParagraph(
WORD_LENGTH, 4 * 1024 * 1024 /* 4mb text */).toString();
final RenderNode node = RenderNode.create("benchmark", null);
- final RenderNode child = RenderNode.create("child", null);
- child.setLeftTopRightBottom(50, 50, 100, 100);
-
- RecordingCanvas canvas = node.start(100, 100);
- node.end(canvas);
- canvas = child.start(50, 50);
- child.end(canvas);
final Random r = new Random(0);
-
while (state.keepRunning()) {
+ state.pauseTiming();
+ RecordingCanvas canvas = node.beginRecording();
int start = r.nextInt(text.length() - 100);
+ state.resumeTiming();
+
canvas.drawText(text, start, start + 100, 0, 0, PAINT);
+
+ state.pauseTiming();
+ node.endRecording();
+ state.resumeTiming();
}
}
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index efcabd8..833cc0f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -226,7 +226,7 @@
mMeasuredTimeNs = 0;
final long startTime = SystemClock.elapsedRealtimeNanos();
- atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+ atm.startRecentsActivity(sRecentsIntent, 0 /* eventTime */, anim);
final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
mMeasuredTimeNs += elapsedTimeNsOfStart;
state.addExtraResult("start", elapsedTimeNsOfStart);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
index 9afa194..7d2b64e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
@@ -47,6 +47,10 @@
public class AppSearchDocument {
private static final String TAG = "AppSearchDocument";
+ /** The default empty namespace.*/
+ // TODO(adorokhine): Allow namespace to be specified in the document.
+ public static final String DEFAULT_NAMESPACE = "";
+
/**
* The maximum number of elements in a repeatable field. Will reject the request if exceed
* this limit.
@@ -450,7 +454,7 @@
*/
public Builder(@NonNull String uri, @NonNull String schemaType) {
mBuilderTypeInstance = (BuilderType) this;
- mProtoBuilder.setUri(uri).setSchema(schemaType);
+ mProtoBuilder.setUri(uri).setSchema(schemaType).setNamespace(DEFAULT_NAMESPACE);
// Set current timestamp for creation timestamp by default.
setCreationTimestampMillis(System.currentTimeMillis());
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchException.java b/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java
similarity index 71%
rename from apex/appsearch/service/java/com/android/server/appsearch/AppSearchException.java
rename to apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java
index 9b705ce..00f6e75 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchException.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,31 +14,38 @@
* limitations under the License.
*/
-package com.android.server.appsearch;
+package android.app.appsearch.exceptions;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.AppSearchResult;
/**
- * An exception thrown by {@link com.android.server.appsearch.AppSearchManagerService} or a
- * subcomponent.
+ * An exception thrown by {@code android.app.appsearch.AppSearchManager} or a subcomponent.
*
- * <p>These exceptions can be converted into a failed {@link android.app.appsearch.AppSearchResult}
+ * <p>These exceptions can be converted into a failed {@link AppSearchResult}
* for propagating to the client.
+ * @hide
*/
+//TODO(b/157082794): Linkify to AppSearchManager once that API is public
public class AppSearchException extends Exception {
private final @AppSearchResult.ResultCode int mResultCode;
- /** Initializes an {@link com.android.server.appsearch.AppSearchException} with no message. */
+ /**
+ * Initializes an {@link AppSearchException} with no message.
+ * @hide
+ */
public AppSearchException(@AppSearchResult.ResultCode int resultCode) {
this(resultCode, /*message=*/ null);
}
+ /** @hide */
public AppSearchException(
@AppSearchResult.ResultCode int resultCode, @Nullable String message) {
this(resultCode, message, /*cause=*/ null);
}
+ /** @hide */
public AppSearchException(
@AppSearchResult.ResultCode int resultCode,
@Nullable String message,
@@ -48,9 +55,9 @@
}
/**
- * Converts this {@link java.lang.Exception} into a failed
- * {@link android.app.appsearch.AppSearchResult}
+ * Converts this {@link java.lang.Exception} into a failed {@link AppSearchResult}
*/
+ @NonNull
public <T> AppSearchResult<T> toAppSearchResult() {
return AppSearchResult.newFailedResult(mResultCode, getMessage());
}
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index c125f56..fc1d707 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -20,7 +20,13 @@
"framework-appsearch",
"services.core",
],
- static_libs: ["icing-java-proto-lite"],
+ static_libs: [
+ "icing-java-proto-lite",
+ "libicing-java",
+ ],
+ required: [
+ "libicing",
+ ],
jarjar_rules: "jarjar-rules.txt",
apex_available: ["com.android.appsearch"],
}
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 16948b2..75fad82 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -17,8 +17,10 @@
import android.annotation.NonNull;
import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchDocument;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.IAppSearchManager;
+import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Binder;
import android.os.UserHandle;
@@ -26,8 +28,7 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
-import com.android.server.appsearch.impl.AppSearchImpl;
-import com.android.server.appsearch.impl.ImplInstanceManager;
+import com.android.server.appsearch.external.localbackend.AppSearchImpl;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.ResultSpecProto;
@@ -44,6 +45,7 @@
* TODO(b/142567528): add comments when implement this class
*/
public class AppSearchManagerService extends SystemService {
+ private static final String TAG = "AppSearchManagerService";
public AppSearchManagerService(Context context) {
super(context);
@@ -68,7 +70,8 @@
try {
SchemaProto schema = SchemaProto.parseFrom(schemaBytes);
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- impl.setSchema(callingUid, schema, forceOverride);
+ String databaseName = makeDatabaseName(callingUid);
+ impl.setSchema(databaseName, schema, forceOverride);
callback.complete(AppSearchResult.newSuccessfulResult(/*value=*/ null));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
@@ -88,13 +91,14 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ String databaseName = makeDatabaseName(callingUid);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
for (int i = 0; i < documentsBytes.size(); i++) {
byte[] documentBytes = (byte[]) documentsBytes.get(i);
DocumentProto document = DocumentProto.parseFrom(documentBytes);
try {
- impl.putDocument(callingUid, document);
+ impl.putDocument(databaseName, document);
resultBuilder.setSuccess(document.getUri(), /*value=*/ null);
} catch (Throwable t) {
resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
@@ -118,12 +122,14 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ String databaseName = makeDatabaseName(callingUid);
AppSearchBatchResult.Builder<String, byte[]> resultBuilder =
new AppSearchBatchResult.Builder<>();
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
- DocumentProto document = impl.getDocument(callingUid, uri);
+ DocumentProto document = impl.getDocument(
+ databaseName, AppSearchDocument.DEFAULT_NAMESPACE, uri);
if (document == null) {
resultBuilder.setFailure(
uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null);
@@ -161,8 +167,9 @@
ResultSpecProto resultSpecProto = ResultSpecProto.parseFrom(resultSpecBytes);
ScoringSpecProto scoringSpecProto = ScoringSpecProto.parseFrom(scoringSpecBytes);
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- SearchResultProto searchResultProto =
- impl.query(callingUid, searchSpecProto, resultSpecProto, scoringSpecProto);
+ String databaseName = makeDatabaseName(callingUid);
+ SearchResultProto searchResultProto = impl.query(
+ databaseName, searchSpecProto, resultSpecProto, scoringSpecProto);
// TODO(sidchhabra): Translate SearchResultProto errors into error codes. This might
// better be done in AppSearchImpl by throwing an AppSearchException.
if (searchResultProto.getStatus().getCode() != StatusProto.Code.OK) {
@@ -190,17 +197,14 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ String databaseName = makeDatabaseName(callingUid);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
- if (!impl.delete(callingUid, uri)) {
- resultBuilder.setFailure(
- uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null);
- } else {
- resultBuilder.setSuccess(uri, /*value= */null);
- }
+ impl.remove(databaseName, AppSearchDocument.DEFAULT_NAMESPACE, uri);
+ resultBuilder.setSuccess(uri, /*value= */null);
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
}
@@ -223,19 +227,14 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ String databaseName = makeDatabaseName(callingUid);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
for (int i = 0; i < schemaTypes.size(); i++) {
String schemaType = schemaTypes.get(i);
try {
- if (!impl.deleteByType(callingUid, schemaType)) {
- resultBuilder.setFailure(
- schemaType,
- AppSearchResult.RESULT_NOT_FOUND,
- /*errorMessage=*/ null);
- } else {
- resultBuilder.setSuccess(schemaType, /*value=*/ null);
- }
+ impl.removeByType(databaseName, schemaType);
+ resultBuilder.setSuccess(schemaType, /*value=*/ null);
} catch (Throwable t) {
resultBuilder.setResult(schemaType, throwableToFailedResult(t));
}
@@ -256,7 +255,8 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- impl.deleteAll(callingUid);
+ String databaseName = makeDatabaseName(callingUid);
+ impl.removeAll(databaseName);
callback.complete(AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
@@ -265,6 +265,25 @@
}
}
+ /**
+ * Returns a unique database name for the given uid.
+ *
+ * <p>The current implementation returns the package name of the app with this uid in a
+ * format like {@code com.example.package} or {@code com.example.sharedname:5678}.
+ */
+ @NonNull
+ private String makeDatabaseName(int callingUid) {
+ // For regular apps, this call will return the package name. If callingUid is an
+ // android:sharedUserId, this value may be another type of name and have a :uid suffix.
+ String callingUidName = getContext().getPackageManager().getNameForUid(callingUid);
+ if (callingUidName == null) {
+ // Not sure how this is possible --- maybe app was uninstalled?
+ throw new IllegalStateException(
+ "Failed to look up package name for uid " + callingUid);
+ }
+ return callingUidName;
+ }
+
private <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
@NonNull Throwable t) {
if (t instanceof AppSearchException) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
similarity index 60%
rename from apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
rename to apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 395e30e..c1e6b0f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -14,21 +14,32 @@
* limitations under the License.
*/
-package com.android.server.appsearch.impl;
+package com.android.server.appsearch;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
+import android.os.Environment;
+import android.os.storage.StorageManager;
import android.util.SparseArray;
+import com.android.server.appsearch.external.localbackend.AppSearchImpl;
+
+import java.io.File;
+
/**
* Manages the lifecycle of instances of {@link AppSearchImpl}.
*
* <p>These instances are managed per unique device-user.
*/
public final class ImplInstanceManager {
+ private static final String APP_SEARCH_DIR = "appSearch";
+
private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
+ private ImplInstanceManager() {}
+
/**
* Gets an instance of AppSearchImpl for the given user.
*
@@ -40,17 +51,33 @@
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId) {
+ public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId)
+ throws AppSearchException {
AppSearchImpl instance = sInstances.get(userId);
if (instance == null) {
synchronized (ImplInstanceManager.class) {
instance = sInstances.get(userId);
if (instance == null) {
- instance = new AppSearchImpl(context, userId);
+ instance = createImpl(context, userId);
sInstances.put(userId, instance);
}
}
}
return instance;
}
+
+ private static AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
+ throws AppSearchException {
+ File appSearchDir = getAppSearchDir(context, userId);
+ AppSearchImpl appSearchImpl = new AppSearchImpl(appSearchDir);
+ appSearchImpl.initialize();
+ return appSearchImpl;
+ }
+
+ private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
+ // See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
+ File userCeDir = Environment.getDataUserCePackageDirectory(
+ StorageManager.UUID_PRIVATE_INTERNAL, userId, context.getPackageName());
+ return new File(userCeDir, APP_SEARCH_DIR);
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java
new file mode 100644
index 0000000..462f458
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java
@@ -0,0 +1,865 @@
+/*
+ * 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 com.android.server.appsearch.external.localbackend;
+
+import android.util.Log;
+
+import android.annotation.AnyThread;
+import com.android.internal.annotations.GuardedBy;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import android.annotation.WorkerThread;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.google.android.icing.IcingSearchEngine;
+import com.google.android.icing.proto.DeleteByNamespaceResultProto;
+import com.google.android.icing.proto.DeleteBySchemaTypeResultProto;
+import com.google.android.icing.proto.DeleteResultProto;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.GetAllNamespacesResultProto;
+import com.google.android.icing.proto.GetOptimizeInfoResultProto;
+import com.google.android.icing.proto.GetResultProto;
+import com.google.android.icing.proto.GetSchemaResultProto;
+import com.google.android.icing.proto.IcingSearchEngineOptions;
+import com.google.android.icing.proto.InitializeResultProto;
+import com.google.android.icing.proto.OptimizeResultProto;
+import com.google.android.icing.proto.PropertyConfigProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.ResetResultProto;
+import com.google.android.icing.proto.ResultSpecProto;
+import com.google.android.icing.proto.SchemaProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SearchSpecProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
+import com.google.android.icing.proto.StatusProto;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Manages interaction with the native IcingSearchEngine and other components to implement AppSearch
+ * functionality.
+ *
+ * <p>Callers should call {@link #initialize} before using the AppSearchImpl instance. Never create
+ * two instances using the same folder.
+ *
+ * <p>A single instance of {@link AppSearchImpl} can support all databases. Schemas and documents
+ * are physically saved together in {@link IcingSearchEngine}, but logically isolated:
+ * <ul>
+ * <li>Rewrite SchemaType in SchemaProto by adding database name prefix and save into
+ * SchemaTypes set in {@link #setSchema}.
+ * <li>Rewrite namespace and SchemaType in DocumentProto by adding database name prefix and
+ * save to namespaces set in {@link #putDocument}.
+ * <li>Remove database name prefix when retrieve documents in {@link #getDocument} and
+ * {@link #query}.
+ * <li>Rewrite filters in {@link SearchSpecProto} to have all namespaces and schema types of
+ * the queried database when user using empty filters in {@link #query}.
+ * </ul>
+ *
+ * <p>Methods in this class belong to two groups, the query group and the mutate group.
+ * <ul>
+ * <li>All methods are going to modify global parameters and data in Icing are executed under
+ * WRITE lock to keep thread safety.
+ * <li>All methods are going to access global parameters or query data from Icing are executed
+ * under READ lock to improve query performance.
+ * </ul>
+ *
+ * <p>This class is thread safe.
+ * @hide
+ */
+
+@WorkerThread
+public final class AppSearchImpl {
+ private static final String TAG = "AppSearchImpl";
+
+ @VisibleForTesting
+ static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
+ @VisibleForTesting
+ static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
+ @VisibleForTesting
+ static final int CHECK_OPTIMIZE_INTERVAL = 100;
+
+ private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
+ private final CountDownLatch mInitCompleteLatch = new CountDownLatch(1);
+ private final File mIcingDir;
+ private IcingSearchEngine mIcingSearchEngine;
+
+ // The map contains schemaTypes and namespaces for all database. All values in the map have
+ // been already added database name prefix.
+ private final Map<String, Set<String>> mSchemaMap = new HashMap<>();
+ private final Map<String, Set<String>> mNamespaceMap = new HashMap<>();
+
+ /**
+ * The counter to check when to call {@link #checkForOptimize(boolean)}. The interval is
+ * {@link #CHECK_OPTIMIZE_INTERVAL}.
+ */
+ private int mOptimizeIntervalCount = 0;
+
+ /** Creates an instance of {@link AppSearchImpl} which writes data to the given folder. */
+ @AnyThread
+ public AppSearchImpl(@NonNull File icingDir) {
+ mIcingDir = icingDir;
+ }
+
+ /**
+ * Initializes the underlying IcingSearchEngine.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @throws AppSearchException on IcingSearchEngine error.
+ */
+ public void initialize() throws AppSearchException {
+ if (isInitialized()) {
+ return;
+ }
+ boolean isReset = false;
+ mReadWriteLock.writeLock().lock();
+ try {
+ // We synchronize here because we don't want to call IcingSearchEngine.initialize() more
+ // than once. It's unnecessary and can be a costly operation.
+ if (isInitialized()) {
+ return;
+ }
+ IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder()
+ .setBaseDir(mIcingDir.getAbsolutePath()).build();
+ mIcingSearchEngine = new IcingSearchEngine(options);
+
+ InitializeResultProto initializeResultProto = mIcingSearchEngine.initialize();
+ SchemaProto schemaProto = null;
+ GetAllNamespacesResultProto getAllNamespacesResultProto = null;
+ try {
+ checkSuccess(initializeResultProto.getStatus());
+ schemaProto = getSchemaProto();
+ getAllNamespacesResultProto = mIcingSearchEngine.getAllNamespaces();
+ checkSuccess(getAllNamespacesResultProto.getStatus());
+ } catch (AppSearchException e) {
+ // Some error. Reset and see if it fixes it.
+ reset();
+ isReset = true;
+ }
+ for (SchemaTypeConfigProto schema : schemaProto.getTypesList()) {
+ String qualifiedSchemaType = schema.getSchemaType();
+ addToMap(mSchemaMap, getDatabaseName(qualifiedSchemaType), qualifiedSchemaType);
+ }
+ for (String qualifiedNamespace : getAllNamespacesResultProto.getNamespacesList()) {
+ addToMap(mNamespaceMap, getDatabaseName(qualifiedNamespace), qualifiedNamespace);
+ }
+ mInitCompleteLatch.countDown();
+ if (!isReset) {
+ checkForOptimize(/* force= */ true);
+ }
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /** Checks if the internal state of {@link AppSearchImpl} has been initialized. */
+ @AnyThread
+ public boolean isInitialized() {
+ return mInitCompleteLatch.getCount() == 0;
+ }
+
+ /**
+ * Updates the AppSearch schema for this app.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The name of the database where this schema lives.
+ * @param origSchema The schema to set for this app.
+ * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
+ * which do not comply with the new schema will be deleted.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void setSchema(@NonNull String databaseName, @NonNull SchemaProto origSchema,
+ boolean forceOverride) throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ SchemaProto schemaProto = getSchemaProto();
+
+ SchemaProto.Builder existingSchemaBuilder = schemaProto.toBuilder();
+
+ // Combine the existing schema (which may have types from other databases) with this
+ // database's new schema. Modifies the existingSchemaBuilder.
+ Set<String> newTypeNames = rewriteSchema(databaseName, existingSchemaBuilder, origSchema);
+
+ SetSchemaResultProto setSchemaResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ setSchemaResultProto = mIcingSearchEngine.setSchema(existingSchemaBuilder.build(),
+ forceOverride);
+ checkSuccess(setSchemaResultProto.getStatus());
+ mSchemaMap.put(databaseName, newTypeNames);
+ if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
+ || (setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0
+ && forceOverride)) {
+ // Any existing schemas which is not in origSchema will be deleted, and all
+ // documents of these types were also deleted. And so well if we force override
+ // incompatible schemas.
+ checkForOptimize(/* force= */true);
+ }
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Adds a document to the AppSearch index.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The databaseName this document resides in.
+ * @param document The document to index.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void putDocument(@NonNull String databaseName, @NonNull DocumentProto document)
+ throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ DocumentProto.Builder documentBuilder = document.toBuilder();
+ rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ true);
+
+ PutResultProto putResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ putResultProto = mIcingSearchEngine.put(documentBuilder.build());
+ addToMap(mNamespaceMap, databaseName, documentBuilder.getNamespace());
+ // The existing documents with same URI will be deleted, so there maybe some resources
+ // could be released after optimize().
+ checkForOptimize(/* force= */false);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ checkSuccess(putResultProto.getStatus());
+ }
+
+ /**
+ * Retrieves a document from the AppSearch index by URI.
+ *
+ * <p>This method belongs to query group.
+ *
+ * @param databaseName The databaseName this document resides in.
+ * @param namespace The namespace this document resides in.
+ * @param uri The URI of the document to get.
+ * @return The Document contents, or {@code null} if no such URI exists in the system.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ @Nullable
+ public DocumentProto getDocument(@NonNull String databaseName, @NonNull String namespace,
+ @NonNull String uri) throws AppSearchException, InterruptedException {
+ awaitInitialized();
+ GetResultProto getResultProto;
+ mReadWriteLock.readLock().lock();
+ try {
+ getResultProto = mIcingSearchEngine.get(
+ getDatabasePrefix(databaseName) + namespace, uri);
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ checkSuccess(getResultProto.getStatus());
+
+ DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
+ rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ false);
+ return documentBuilder.build();
+ }
+
+ /**
+ * Executes a query against the AppSearch index and returns results.
+ *
+ * <p>This method belongs to query group.
+ *
+ * @param databaseName The databaseName this query for.
+ * @param searchSpec Defines what and how to search
+ * @param resultSpec Defines what results to show
+ * @param scoringSpec Defines how to order results
+ * @return The results of performing this search The proto might have no {@code results} if no
+ * documents matched the query.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ @NonNull
+ public SearchResultProto query(
+ @NonNull String databaseName,
+ @NonNull SearchSpecProto searchSpec,
+ @NonNull ResultSpecProto resultSpec,
+ @NonNull ScoringSpecProto scoringSpec) throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ SearchSpecProto.Builder searchSpecBuilder = searchSpec.toBuilder();
+ SearchResultProto searchResultProto;
+ mReadWriteLock.readLock().lock();
+ try {
+ // Only rewrite SearchSpec for non empty database.
+ // rewriteSearchSpecForNonEmptyDatabase will return false for empty database, we
+ // should just return an empty SearchResult and skip sending request to Icing.
+ if (!rewriteSearchSpecForNonEmptyDatabase(databaseName, searchSpecBuilder)) {
+ return SearchResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder()
+ .setCode(StatusProto.Code.OK)
+ .build())
+ .build();
+ }
+ searchResultProto = mIcingSearchEngine.search(
+ searchSpecBuilder.build(), scoringSpec, resultSpec);
+ } finally {
+ mReadWriteLock.readLock().unlock();
+ }
+ checkSuccess(searchResultProto.getStatus());
+ if (searchResultProto.getResultsCount() == 0) {
+ return searchResultProto;
+ }
+ return rewriteSearchResultProto(databaseName, searchResultProto);
+ }
+
+ /**
+ * Fetches the next page of results of a previously executed query. Results can be empty if
+ * next-page token is invalid or all pages have been returned.
+ *
+ * @param databaseName The databaseName of the previously executed query.
+ * @param nextPageToken The token of pre-loaded results of previously executed query.
+ * @return The next page of results of previously executed query.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ @NonNull
+ public SearchResultProto getNextPage(@NonNull String databaseName, long nextPageToken)
+ throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ SearchResultProto searchResultProto = mIcingSearchEngine.getNextPage(nextPageToken);
+ checkSuccess(searchResultProto.getStatus());
+ if (searchResultProto.getResultsCount() == 0) {
+ return searchResultProto;
+ }
+ return rewriteSearchResultProto(databaseName, searchResultProto);
+ }
+
+ /**
+ * Invalidates the next-page token so that no more results of the related query can be returned.
+ * @param nextPageToken The token of pre-loaded results of previously executed query to be
+ * Invalidated.
+ */
+ public void invalidateNextPageToken(long nextPageToken) throws InterruptedException {
+ awaitInitialized();
+ mIcingSearchEngine.invalidateNextPageToken(nextPageToken);
+ }
+
+ /**
+ * Removes the given document by URI.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The databaseName the document is in.
+ * @param namespace Namespace of the document to remove.
+ * @param uri URI of the document to remove.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void remove(@NonNull String databaseName, @NonNull String namespace,
+ @NonNull String uri) throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
+ DeleteResultProto deleteResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ deleteResultProto = mIcingSearchEngine.delete(qualifiedNamespace, uri);
+ checkForOptimize(/* force= */false);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ checkSuccess(deleteResultProto.getStatus());
+ }
+
+ /**
+ * Removes all documents having the given {@code schemaType} in given database.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The databaseName that contains documents of schemaType.
+ * @param schemaType The schemaType of documents to remove.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void removeByType(@NonNull String databaseName, @NonNull String schemaType)
+ throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ String qualifiedType = getDatabasePrefix(databaseName) + schemaType;
+ DeleteBySchemaTypeResultProto deleteBySchemaTypeResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ Set<String> existingSchemaTypes = mSchemaMap.get(databaseName);
+ if (existingSchemaTypes == null || !existingSchemaTypes.contains(qualifiedType)) {
+ return;
+ }
+ deleteBySchemaTypeResultProto = mIcingSearchEngine.deleteBySchemaType(qualifiedType);
+ checkForOptimize(/* force= */true);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ checkSuccess(deleteBySchemaTypeResultProto.getStatus());
+ }
+
+ /**
+ * Removes all documents having the given {@code namespace} in given database.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The databaseName that contains documents of namespace.
+ * @param namespace The namespace of documents to remove.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void removeByNamespace(@NonNull String databaseName, @NonNull String namespace)
+ throws AppSearchException, InterruptedException {
+ awaitInitialized();
+
+ String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
+ DeleteByNamespaceResultProto deleteByNamespaceResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
+ if (existingNamespaces == null || !existingNamespaces.contains(qualifiedNamespace)) {
+ return;
+ }
+ deleteByNamespaceResultProto = mIcingSearchEngine.deleteByNamespace(qualifiedNamespace);
+ checkForOptimize(/* force= */true);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ checkSuccess(deleteByNamespaceResultProto.getStatus());
+ }
+
+ /**
+ * Clears the given database by removing all documents and types.
+ *
+ * <p>The schemas will remain. To clear everything including schemas, please call
+ * {@link #setSchema} with an empty schema and {@code forceOverride} set to true.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @param databaseName The databaseName to remove all documents from.
+ * @throws AppSearchException on IcingSearchEngine error.
+ * @throws InterruptedException if the current thread was interrupted during execution.
+ */
+ public void removeAll(@NonNull String databaseName)
+ throws AppSearchException, InterruptedException {
+ awaitInitialized();
+ mReadWriteLock.writeLock().lock();
+ try {
+ Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
+ if (existingNamespaces == null) {
+ return;
+ }
+ for (String namespace : existingNamespaces) {
+ DeleteByNamespaceResultProto deleteByNamespaceResultProto =
+ mIcingSearchEngine.deleteByNamespace(namespace);
+ // There's no way for AppSearch to know that all documents in a particular
+ // namespace have been deleted, but if you try to delete an empty namespace, Icing
+ // returns NOT_FOUND. Just ignore that code.
+ checkCodeOneOf(
+ deleteByNamespaceResultProto.getStatus(),
+ StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
+ }
+ mNamespaceMap.remove(databaseName);
+ checkForOptimize(/* force= */true);
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Clears documents and schema across all databaseNames.
+ *
+ * <p>This method belongs to mutate group.
+ *
+ * @throws AppSearchException on IcingSearchEngine error.
+ */
+ @VisibleForTesting
+ public void reset() throws AppSearchException {
+ ResetResultProto resetResultProto;
+ mReadWriteLock.writeLock().lock();
+ try {
+ resetResultProto = mIcingSearchEngine.reset();
+ mOptimizeIntervalCount = 0;
+ mSchemaMap.clear();
+ mNamespaceMap.clear();
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ checkSuccess(resetResultProto.getStatus());
+ }
+
+ /**
+ * Rewrites all types mentioned in the given {@code newSchema} to prepend {@code prefix}.
+ * Rewritten types will be added to the {@code existingSchema}.
+ *
+ * @param databaseName The name of the database where this schema lives.
+ * @param existingSchema A schema that may contain existing types from across all database
+ * instances. Will be mutated to contain the properly rewritten schema
+ * types from {@code newSchema}.
+ * @param newSchema Schema with types to add to the {@code existingSchema}.
+ * @return a Set contains all remaining qualified schema type names in given database.
+ */
+ @VisibleForTesting
+ Set<String> rewriteSchema(@NonNull String databaseName,
+ @NonNull SchemaProto.Builder existingSchema,
+ @NonNull SchemaProto newSchema) throws AppSearchException {
+ String prefix = getDatabasePrefix(databaseName);
+ HashMap<String, SchemaTypeConfigProto> newTypesToProto = new HashMap<>();
+ // Rewrite the schema type to include the typePrefix.
+ for (int typeIdx = 0; typeIdx < newSchema.getTypesCount(); typeIdx++) {
+ SchemaTypeConfigProto.Builder typeConfigBuilder =
+ newSchema.getTypes(typeIdx).toBuilder();
+
+ // Rewrite SchemaProto.types.schema_type
+ String newSchemaType = prefix + typeConfigBuilder.getSchemaType();
+ typeConfigBuilder.setSchemaType(newSchemaType);
+
+ // Rewrite SchemaProto.types.properties.schema_type
+ for (int propertyIdx = 0;
+ propertyIdx < typeConfigBuilder.getPropertiesCount();
+ propertyIdx++) {
+ PropertyConfigProto.Builder propertyConfigBuilder =
+ typeConfigBuilder.getProperties(propertyIdx).toBuilder();
+ if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
+ String newPropertySchemaType =
+ prefix + propertyConfigBuilder.getSchemaType();
+ propertyConfigBuilder.setSchemaType(newPropertySchemaType);
+ typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
+ }
+ }
+
+ newTypesToProto.put(newSchemaType, typeConfigBuilder.build());
+ }
+
+ Set<String> newSchemaTypesName = newTypesToProto.keySet();
+
+ // Combine the existing schema (which may have types from other databases) with this
+ // database's new schema. Modifies the existingSchemaBuilder.
+ // Check if we need to replace any old schema types with the new ones.
+ for (int i = 0; i < existingSchema.getTypesCount(); i++) {
+ String schemaType = existingSchema.getTypes(i).getSchemaType();
+ SchemaTypeConfigProto newProto = newTypesToProto.remove(schemaType);
+ if (newProto != null) {
+ // Replacement
+ existingSchema.setTypes(i, newProto);
+ } else if (databaseName.equals(getDatabaseName(schemaType))) {
+ // All types existing before but not in newSchema should be removed.
+ existingSchema.removeTypes(i);
+ --i;
+ }
+ }
+ // We've been removing existing types from newTypesToProto, so everything that remains is
+ // new.
+ existingSchema.addAllTypes(newTypesToProto.values());
+
+ return newSchemaTypesName;
+ }
+
+ /**
+ * Rewrites all types and namespaces mentioned anywhere in {@code documentBuilder} to prepend
+ * or remove {@code prefix}.
+ *
+ * @param prefix The prefix to add or remove
+ * @param documentBuilder The document to mutate
+ * @param add Whether to add prefix to the types and namespaces. If {@code false},
+ * prefix will be removed.
+ * @throws IllegalStateException If {@code add=false} and the document has a type or namespace
+ * that doesn't start with {@code prefix}.
+ */
+ @VisibleForTesting
+ void rewriteDocumentTypes(
+ @NonNull String prefix,
+ @NonNull DocumentProto.Builder documentBuilder,
+ boolean add) {
+ // Rewrite the type name to include/remove the prefix.
+ String newSchema;
+ if (add) {
+ newSchema = prefix + documentBuilder.getSchema();
+ } else {
+ newSchema = removePrefix(prefix, "schemaType", documentBuilder.getSchema());
+ }
+ documentBuilder.setSchema(newSchema);
+
+ // Rewrite the namespace to include/remove the prefix.
+ if (add) {
+ documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
+ } else {
+ documentBuilder.setNamespace(
+ removePrefix(prefix, "namespace", documentBuilder.getNamespace()));
+ }
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ rewriteDocumentTypes(prefix, derivedDocumentBuilder, add);
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+ }
+
+ /**
+ * Rewrites searchSpec by adding schemaTypeFilter and namespacesFilter
+ *
+ * <p>If user input empty filter lists, will look up {@link #mSchemaMap} and
+ * {@link #mNamespaceMap} and put all values belong to current database to narrow down Icing
+ * search area.
+ * <p>This method should be only called in query methods and get the READ lock to keep thread
+ * safety.
+ * @return false if the current database is brand new and contains nothing. We should just
+ * return an empty query result to user.
+ */
+ @VisibleForTesting
+ @GuardedBy("mReadWriteLock")
+ boolean rewriteSearchSpecForNonEmptyDatabase(@NonNull String databaseName,
+ @NonNull SearchSpecProto.Builder searchSpecBuilder) {
+ Set<String> existingSchemaTypes = mSchemaMap.get(databaseName);
+ Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
+ if (existingSchemaTypes == null || existingSchemaTypes.isEmpty()
+ || existingNamespaces == null || existingNamespaces.isEmpty()) {
+ return false;
+ }
+ // Rewrite any existing schema types specified in the searchSpec, or add schema types to
+ // limit the search to this database instance.
+ if (searchSpecBuilder.getSchemaTypeFiltersCount() > 0) {
+ for (int i = 0; i < searchSpecBuilder.getSchemaTypeFiltersCount(); i++) {
+ String qualifiedType = getDatabasePrefix(databaseName)
+ + searchSpecBuilder.getSchemaTypeFilters(i);
+ if (existingSchemaTypes.contains(qualifiedType)) {
+ searchSpecBuilder.setSchemaTypeFilters(i, qualifiedType);
+ }
+ }
+ } else {
+ searchSpecBuilder.addAllSchemaTypeFilters(existingSchemaTypes);
+ }
+
+ // Rewrite any existing namespaces specified in the searchSpec, or add namespaces to
+ // limit the search to this database instance.
+ if (searchSpecBuilder.getNamespaceFiltersCount() > 0) {
+ for (int i = 0; i < searchSpecBuilder.getNamespaceFiltersCount(); i++) {
+ String qualifiedNamespace = getDatabasePrefix(databaseName)
+ + searchSpecBuilder.getNamespaceFilters(i);
+ searchSpecBuilder.setNamespaceFilters(i, qualifiedNamespace);
+ }
+ } else {
+ searchSpecBuilder.addAllNamespaceFilters(existingNamespaces);
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ SchemaProto getSchemaProto() throws AppSearchException {
+ GetSchemaResultProto schemaProto = mIcingSearchEngine.getSchema();
+ // TODO(b/161935693) check GetSchemaResultProto is success or not. Call reset() if it's not.
+ // TODO(b/161935693) only allow GetSchemaResultProto NOT_FOUND on first run
+ checkCodeOneOf(schemaProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
+ return schemaProto.getSchema();
+ }
+
+ @NonNull
+ private String getDatabasePrefix(@NonNull String databaseName) {
+ return databaseName + "/";
+ }
+
+ @NonNull
+ private String getDatabaseName(@NonNull String prefixedValue) throws AppSearchException {
+ int delimiterIndex = prefixedValue.indexOf('/');
+ if (delimiterIndex == -1) {
+ throw new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "The databaseName prefixed value doesn't contains a valid database name.");
+ }
+ return prefixedValue.substring(0, delimiterIndex);
+ }
+
+ @NonNull
+ private static String removePrefix(@NonNull String prefix, @NonNull String inputType,
+ @NonNull String input) {
+ if (!input.startsWith(prefix)) {
+ throw new IllegalStateException(
+ "Unexpected " + inputType + " \"" + input
+ + "\" does not start with \"" + prefix + "\"");
+ }
+ return input.substring(prefix.length());
+ }
+
+ @GuardedBy("mReadWriteLock")
+ private void addToMap(Map<String, Set<String>> map, String databaseName, String prefixedValue) {
+ Set<String> values = map.get(databaseName);
+ if (values == null) {
+ values = new HashSet<>();
+ map.put(databaseName, values);
+ }
+ values.add(prefixedValue);
+ }
+
+ /**
+ * Waits for the instance to become initialized.
+ *
+ * @throws InterruptedException if the current thread was interrupted during waiting.
+ */
+ private void awaitInitialized() throws InterruptedException {
+ mInitCompleteLatch.await();
+ }
+
+ /**
+ * Checks the given status code and throws an {@link AppSearchException} if code is an error.
+ *
+ * @throws AppSearchException on error codes.
+ */
+ private void checkSuccess(StatusProto statusProto) throws AppSearchException {
+ checkCodeOneOf(statusProto, StatusProto.Code.OK);
+ }
+
+ /**
+ * Checks the given status code is one of the provided codes, and throws an
+ * {@link AppSearchException} if it is not.
+ */
+ private void checkCodeOneOf(StatusProto statusProto, StatusProto.Code... codes)
+ throws AppSearchException {
+ for (int i = 0; i < codes.length; i++) {
+ if (codes[i] == statusProto.getCode()) {
+ // Everything's good
+ return;
+ }
+ }
+
+ if (statusProto.getCode() == StatusProto.Code.WARNING_DATA_LOSS) {
+ // TODO: May want to propagate WARNING_DATA_LOSS up to AppSearchManager so they can
+ // choose to log the error or potentially pass it on to clients.
+ Log.w(TAG, "Encountered WARNING_DATA_LOSS: " + statusProto.getMessage());
+ return;
+ }
+
+ throw statusProtoToAppSearchException(statusProto);
+ }
+
+ /**
+ * Checks whether {@link IcingSearchEngine#optimize()} should be called to release resources.
+ *
+ * <p>This method should be only called in mutate methods and get the WRITE lock to keep thread
+ * safety.
+ * <p>{@link IcingSearchEngine#optimize()} should be called only if
+ * {@link GetOptimizeInfoResultProto} shows there is enough resources could be released.
+ * <p>{@link IcingSearchEngine#getOptimizeInfo()} should be called once per
+ * {@link #CHECK_OPTIMIZE_INTERVAL} of remove executions.
+ *
+ * @param force whether we should directly call {@link IcingSearchEngine#getOptimizeInfo()}.
+ */
+ @GuardedBy("mReadWriteLock")
+ private void checkForOptimize(boolean force) throws AppSearchException {
+ ++mOptimizeIntervalCount;
+ if (force || mOptimizeIntervalCount >= CHECK_OPTIMIZE_INTERVAL) {
+ mOptimizeIntervalCount = 0;
+ GetOptimizeInfoResultProto optimizeInfo = getOptimizeInfoResult();
+ checkSuccess(optimizeInfo.getStatus());
+ // Second threshold, decide when to call optimize().
+ if (optimizeInfo.getOptimizableDocs() >= OPTIMIZE_THRESHOLD_DOC_COUNT
+ || optimizeInfo.getEstimatedOptimizableBytes()
+ >= OPTIMIZE_THRESHOLD_BYTES) {
+ // TODO(b/155939114): call optimize in the same thread will slow down api calls
+ // significantly. Move this call to background.
+ OptimizeResultProto optimizeResultProto = mIcingSearchEngine.optimize();
+ checkSuccess(optimizeResultProto.getStatus());
+ }
+ // TODO(b/147699081): Return OptimizeResultProto & log lost data detail once we add
+ // a field to indicate lost_schema and lost_documents in OptimizeResultProto.
+ // go/icing-library-apis.
+ }
+ }
+
+ /** Remove the rewritten schema types from any result documents.*/
+ private SearchResultProto rewriteSearchResultProto(@NonNull String databaseName,
+ @NonNull SearchResultProto searchResultProto) {
+ SearchResultProto.Builder searchResultsBuilder = searchResultProto.toBuilder();
+ for (int i = 0; i < searchResultsBuilder.getResultsCount(); i++) {
+ if (searchResultProto.getResults(i).hasDocument()) {
+ SearchResultProto.ResultProto.Builder resultBuilder =
+ searchResultsBuilder.getResults(i).toBuilder();
+ DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
+ rewriteDocumentTypes(
+ getDatabasePrefix(databaseName), documentBuilder, /*add=*/false);
+ resultBuilder.setDocument(documentBuilder);
+ searchResultsBuilder.setResults(i, resultBuilder);
+ }
+ }
+ return searchResultsBuilder.build();
+ }
+
+ @VisibleForTesting
+ GetOptimizeInfoResultProto getOptimizeInfoResult() {
+ return mIcingSearchEngine.getOptimizeInfo();
+ }
+
+ /**
+ * Converts an erroneous status code to an AppSearchException. Callers should ensure that
+ * the status code is not OK or WARNING_DATA_LOSS.
+ *
+ * @param statusProto StatusProto with error code and message to translate into
+ * AppSearchException.
+ * @return AppSearchException with the parallel error code.
+ */
+ private AppSearchException statusProtoToAppSearchException(StatusProto statusProto) {
+ switch (statusProto.getCode()) {
+ case INVALID_ARGUMENT:
+ return new AppSearchException(AppSearchResult.RESULT_INVALID_ARGUMENT,
+ statusProto.getMessage());
+ case NOT_FOUND:
+ return new AppSearchException(AppSearchResult.RESULT_NOT_FOUND,
+ statusProto.getMessage());
+ case FAILED_PRECONDITION:
+ // Fallthrough
+ case ABORTED:
+ // Fallthrough
+ case INTERNAL:
+ return new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
+ statusProto.getMessage());
+ case OUT_OF_SPACE:
+ return new AppSearchException(AppSearchResult.RESULT_OUT_OF_SPACE,
+ statusProto.getMessage());
+ default:
+ // Some unknown/unsupported error
+ return new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "Unknown IcingSearchEngine status code: " + statusProto.getCode());
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
deleted file mode 100644
index 4358d20..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.ResultSpecProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.ScoringSpecProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
-
-import java.util.Set;
-
-/**
- * Manages interaction with {@link FakeIcing} and other components to implement AppSearch
- * functionality.
- */
-public final class AppSearchImpl {
- private final Context mContext;
- private final @UserIdInt int mUserId;
- private final FakeIcing mFakeIcing = new FakeIcing();
-
- AppSearchImpl(@NonNull Context context, @UserIdInt int userId) {
- mContext = context;
- mUserId = userId;
- }
-
- /**
- * Updates the AppSearch schema for this app.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param origSchema The schema to set for this app.
- * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
- * which do not comply with the new schema will be deleted.
- */
- public void setSchema(int callingUid, @NonNull SchemaProto origSchema, boolean forceOverride) {
- // Rewrite schema type names to include the calling app's package and uid.
- String typePrefix = getTypePrefix(callingUid);
- SchemaProto.Builder schemaBuilder = origSchema.toBuilder();
- rewriteSchemaTypes(typePrefix, schemaBuilder);
-
- // TODO(b/145635424): Save in schema type map
- // TODO(b/145635424): Apply the schema to Icing and report results
- }
-
- /**
- * Rewrites all types mentioned in the given {@code schemaBuilder} to prepend
- * {@code typePrefix}.
- *
- * @param typePrefix The prefix to add
- * @param schemaBuilder The schema to mutate
- */
- @VisibleForTesting
- void rewriteSchemaTypes(
- @NonNull String typePrefix, @NonNull SchemaProto.Builder schemaBuilder) {
- for (int typeIdx = 0; typeIdx < schemaBuilder.getTypesCount(); typeIdx++) {
- SchemaTypeConfigProto.Builder typeConfigBuilder =
- schemaBuilder.getTypes(typeIdx).toBuilder();
-
- // Rewrite SchemaProto.types.schema_type
- String newSchemaType = typePrefix + typeConfigBuilder.getSchemaType();
- typeConfigBuilder.setSchemaType(newSchemaType);
-
- // Rewrite SchemaProto.types.properties.schema_type
- for (int propertyIdx = 0;
- propertyIdx < typeConfigBuilder.getPropertiesCount();
- propertyIdx++) {
- PropertyConfigProto.Builder propertyConfigBuilder =
- typeConfigBuilder.getProperties(propertyIdx).toBuilder();
- if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
- String newPropertySchemaType =
- typePrefix + propertyConfigBuilder.getSchemaType();
- propertyConfigBuilder.setSchemaType(newPropertySchemaType);
- typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
- }
- }
-
- schemaBuilder.setTypes(typeIdx, typeConfigBuilder);
- }
- }
-
- /**
- * Adds a document to the AppSearch index.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param origDocument The document to index.
- */
- public void putDocument(int callingUid, @NonNull DocumentProto origDocument) {
- // Rewrite the type names to include the app's prefix
- String typePrefix = getTypePrefix(callingUid);
- DocumentProto.Builder documentBuilder = origDocument.toBuilder();
- rewriteDocumentTypes(typePrefix, documentBuilder, /*add=*/ true);
- mFakeIcing.put(documentBuilder.build());
- }
-
- /**
- * Retrieves a document from the AppSearch index by URI.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param uri The URI of the document to get.
- * @return The Document contents, or {@code null} if no such URI exists in the system.
- */
- @Nullable
- public DocumentProto getDocument(int callingUid, @NonNull String uri) {
- String typePrefix = getTypePrefix(callingUid);
- DocumentProto document = mFakeIcing.get(uri);
- if (document == null) {
- return null;
- }
-
- // TODO(b/146526096): Since FakeIcing doesn't currently handle namespaces, we perform a
- // post-filter to make sure we don't return documents we shouldn't. This should be removed
- // once the real Icing Lib is implemented.
- if (!document.getNamespace().equals(typePrefix)) {
- return null;
- }
-
- // Rewrite the type names to remove the app's prefix
- DocumentProto.Builder documentBuilder = document.toBuilder();
- rewriteDocumentTypes(typePrefix, documentBuilder, /*add=*/ false);
- return documentBuilder.build();
- }
-
- /**
- * Executes a query against the AppSearch index and returns results.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param searchSpec Defines what and how to search
- * @param resultSpec Defines what results to show
- * @param scoringSpec Defines how to order results
- * @return The results of performing this search The proto might have no {@code results} if no
- * documents matched the query.
- */
- @NonNull
- public SearchResultProto query(
- int callingUid,
- @NonNull SearchSpecProto searchSpec,
- @NonNull ResultSpecProto resultSpec,
- @NonNull ScoringSpecProto scoringSpec) {
- String typePrefix = getTypePrefix(callingUid);
- SearchResultProto searchResults = mFakeIcing.query(searchSpec.getQuery());
- if (searchResults.getResultsCount() == 0) {
- return searchResults;
- }
- Set<String> qualifiedSearchFilters = null;
- if (searchSpec.getSchemaTypeFiltersCount() > 0) {
- qualifiedSearchFilters = new ArraySet<>(searchSpec.getSchemaTypeFiltersCount());
- for (String schema : searchSpec.getSchemaTypeFiltersList()) {
- String qualifiedSchema = typePrefix + schema;
- qualifiedSearchFilters.add(qualifiedSchema);
- }
- }
- // Rewrite the type names to remove the app's prefix
- SearchResultProto.Builder searchResultsBuilder = searchResults.toBuilder();
- for (int i = 0; i < searchResultsBuilder.getResultsCount(); i++) {
- if (searchResults.getResults(i).hasDocument()) {
- SearchResultProto.ResultProto.Builder resultBuilder =
- searchResultsBuilder.getResults(i).toBuilder();
-
- // TODO(b/145631811): Since FakeIcing doesn't currently handle namespaces, we
- // perform a post-filter to make sure we don't return documents we shouldn't. This
- // should be removed once the real Icing Lib is implemented.
- if (!resultBuilder.getDocument().getNamespace().equals(typePrefix)) {
- searchResultsBuilder.removeResults(i);
- i--;
- continue;
- }
-
- // TODO(b/145631811): Since FakeIcing doesn't currently handle type names, we
- // perform a post-filter to make sure we don't return documents we shouldn't. This
- // should be removed once the real Icing Lib is implemented.
- if (qualifiedSearchFilters != null
- && !qualifiedSearchFilters.contains(
- resultBuilder.getDocument().getSchema())) {
- searchResultsBuilder.removeResults(i);
- i--;
- continue;
- }
-
- DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
- rewriteDocumentTypes(typePrefix, documentBuilder, /*add=*/false);
- resultBuilder.setDocument(documentBuilder);
- searchResultsBuilder.setResults(i, resultBuilder);
- }
- }
- return searchResultsBuilder.build();
- }
-
- /** Deletes the given document by URI */
- public boolean delete(int callingUid, @NonNull String uri) {
- DocumentProto document = mFakeIcing.get(uri);
- if (document == null) {
- return false;
- }
-
- // TODO(b/146526096): Since FakeIcing doesn't currently handle namespaces, we perform a
- // post-filter to make sure we don't delete documents we shouldn't. This should be
- // removed once the real Icing Lib is implemented.
- String typePrefix = getTypePrefix(callingUid);
- if (!typePrefix.equals(document.getNamespace())) {
- throw new SecurityException(
- "Failed to delete document " + uri + "; URI collision in FakeIcing");
- }
-
- return mFakeIcing.delete(uri);
- }
-
- /** Deletes all documents having the given {@code schemaType}. */
- public boolean deleteByType(int callingUid, @NonNull String schemaType) {
- String typePrefix = getTypePrefix(callingUid);
- String qualifiedType = typePrefix + schemaType;
- return mFakeIcing.deleteByType(qualifiedType);
- }
-
- /**
- * Deletes all documents owned by the calling app.
- *
- * @param callingUid The uid of the app calling AppSearch.
- */
- public void deleteAll(int callingUid) {
- String namespace = getTypePrefix(callingUid);
- mFakeIcing.deleteByNamespace(namespace);
- }
-
- /**
- * Rewrites all types mentioned anywhere in {@code documentBuilder} to prepend or remove
- * {@code typePrefix}.
- *
- * @param typePrefix The prefix to add or remove
- * @param documentBuilder The document to mutate
- * @param add Whether to add typePrefix to the types. If {@code false}, typePrefix will be
- * removed from the types.
- * @throws IllegalArgumentException If {@code add=false} and the document has a type that
- * doesn't start with {@code typePrefix}.
- */
- @VisibleForTesting
- void rewriteDocumentTypes(
- @NonNull String typePrefix,
- @NonNull DocumentProto.Builder documentBuilder,
- boolean add) {
- // Rewrite the type name to include/remove the app's prefix
- String newSchema;
- if (add) {
- newSchema = typePrefix + documentBuilder.getSchema();
- } else {
- newSchema = removePrefix(typePrefix, documentBuilder.getSchema());
- }
- documentBuilder.setSchema(newSchema);
-
- // Add/remove namespace. If we ever allow users to set their own namespaces, this will have
- // to change to prepend the prefix instead of setting the whole namespace. We will also have
- // to store the namespaces in a map similar to the type map so we can rewrite queries with
- // empty namespaces.
- if (add) {
- documentBuilder.setNamespace(typePrefix);
- } else if (!documentBuilder.getNamespace().equals(typePrefix)) {
- throw new IllegalStateException(
- "Unexpected namespace \"" + documentBuilder.getNamespace()
- + "\" (expected \"" + typePrefix + "\")");
- } else {
- documentBuilder.clearNamespace();
- }
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- rewriteDocumentTypes(typePrefix, derivedDocumentBuilder, add);
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
- }
-
- /**
- * Returns a type prefix in a format like {@code com.example.package@1000/} or
- * {@code com.example.sharedname:5678@1000/}.
- */
- @NonNull
- private String getTypePrefix(int callingUid) {
- // For regular apps, this call will return the package name. If callingUid is an
- // android:sharedUserId, this value may be another type of name and have a :uid suffix.
- String callingUidName = mContext.getPackageManager().getNameForUid(callingUid);
- if (callingUidName == null) {
- // Not sure how this is possible --- maybe app was uninstalled?
- throw new IllegalStateException("Failed to look up package name for uid " + callingUid);
- }
- return callingUidName + "@" + mUserId + "/";
- }
-
- @NonNull
- private static String removePrefix(@NonNull String prefix, @NonNull String input) {
- if (!input.startsWith(prefix)) {
- throw new IllegalArgumentException(
- "Input \"" + input + "\" does not start with \"" + prefix + "\"");
- }
- return input.substring(prefix.length());
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
deleted file mode 100644
index da15734..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.StatusProto;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Fake in-memory implementation of the Icing key-value store and reverse index.
- * <p>
- * Currently, only queries by single exact term are supported. There is no support for persistence,
- * namespaces, i18n tokenization, or schema.
- */
-public class FakeIcing {
- private final AtomicInteger mNextDocId = new AtomicInteger();
- private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
- /** Array of Documents where index into the array is the docId. */
- private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
- /** Map of term to posting-list (the set of DocIds containing that term). */
- private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
-
- /**
- * Inserts a document into the index.
- *
- * @param document The document to insert.
- */
- public void put(@NonNull DocumentProto document) {
- String uri = document.getUri();
-
- // Update mDocIdMap
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId != null) {
- // Delete the old doc
- mDocStore.remove(docId);
- }
-
- // Allocate a new docId
- docId = mNextDocId.getAndIncrement();
- mUriToDocIdMap.put(uri, docId);
-
- // Update mDocStore
- mDocStore.put(docId, document);
-
- // Update mIndex
- indexDocument(docId, document);
- }
-
- /**
- * Retrieves a document from the index.
- *
- * @param uri The URI of the document to retrieve.
- * @return The body of the document, or {@code null} if no such document exists.
- */
- @Nullable
- public DocumentProto get(@NonNull String uri) {
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId == null) {
- return null;
- }
- return mDocStore.get(docId);
- }
-
- /**
- * Returns documents containing all words in the given query string.
- *
- * @param queryExpression A set of words to search for. They will be implicitly AND-ed together.
- * No operators are supported.
- * @return A {@link SearchResultProto} containing the matching documents, which may have no
- * results if no documents match.
- */
- @NonNull
- public SearchResultProto query(@NonNull String queryExpression) {
- String[] terms = normalizeString(queryExpression).split("\\s+");
- SearchResultProto.Builder results = SearchResultProto.newBuilder()
- .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK));
- if (terms.length == 0) {
- return results.build();
- }
- Set<Integer> docIds = mIndex.get(terms[0]);
- if (docIds == null || docIds.isEmpty()) {
- return results.build();
- }
- for (int i = 1; i < terms.length; i++) {
- Set<Integer> termDocIds = mIndex.get(terms[i]);
- if (termDocIds == null) {
- return results.build();
- }
- docIds.retainAll(termDocIds);
- if (docIds.isEmpty()) {
- return results.build();
- }
- }
- for (int docId : docIds) {
- DocumentProto document = mDocStore.get(docId);
- if (document != null) {
- results.addResults(
- SearchResultProto.ResultProto.newBuilder().setDocument(document));
- }
- }
- return results.build();
- }
-
- /**
- * Deletes a document by its URI.
- *
- * @param uri The URI of the document to be deleted.
- * @return Whether deletion was successful.
- */
- public boolean delete(@NonNull String uri) {
- // Update mDocIdMap
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId != null) {
- // Delete the old doc
- mDocStore.remove(docId);
- mUriToDocIdMap.remove(uri);
- return true;
- }
- return false;
- }
-
- /** Deletes all documents having the given namespace. */
- public void deleteByNamespace(@NonNull String namespace) {
- for (int i = 0; i < mDocStore.size(); i++) {
- DocumentProto document = mDocStore.valueAt(i);
- if (namespace.equals(document.getNamespace())) {
- mDocStore.removeAt(i);
- mUriToDocIdMap.remove(document.getUri());
- i--;
- }
- }
- }
-
- /**
- * Deletes all documents having the given type.
- *
- * @return true if any documents were deleted.
- */
- public boolean deleteByType(@NonNull String type) {
- boolean deletedAny = false;
- for (int i = 0; i < mDocStore.size(); i++) {
- DocumentProto document = mDocStore.valueAt(i);
- if (type.equals(document.getSchema())) {
- mDocStore.removeAt(i);
- mUriToDocIdMap.remove(document.getUri());
- i--;
- deletedAny = true;
- }
- }
- return deletedAny;
- }
-
- private void indexDocument(int docId, DocumentProto document) {
- for (PropertyProto property : document.getPropertiesList()) {
- for (String stringValue : property.getStringValuesList()) {
- String[] words = normalizeString(stringValue).split("\\s+");
- for (String word : words) {
- indexTerm(docId, word);
- }
- }
- for (Long longValue : property.getInt64ValuesList()) {
- indexTerm(docId, longValue.toString());
- }
- for (Double doubleValue : property.getDoubleValuesList()) {
- indexTerm(docId, doubleValue.toString());
- }
- for (Boolean booleanValue : property.getBooleanValuesList()) {
- indexTerm(docId, booleanValue.toString());
- }
- // Intentionally skipping bytes values
- for (DocumentProto documentValue : property.getDocumentValuesList()) {
- indexDocument(docId, documentValue);
- }
- }
- }
-
- private void indexTerm(int docId, String term) {
- Set<Integer> postingList = mIndex.get(term);
- if (postingList == null) {
- postingList = new ArraySet<>();
- mIndex.put(term, postingList);
- }
- postingList.add(docId);
- }
-
- /** Strips out punctuation and converts to lowercase. */
- private static String normalizeString(String input) {
- return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
- }
-}
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index d2826d0..2b69863 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,14 +1,14 @@
// Signature format: 2.0
package android.media {
- public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
- ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
- method public int describeContents();
- method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
- method public java.util.List<T> getList();
- method public void setInlineCountLimit(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
+ @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
+ ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
+ method @Deprecated public java.util.List<T> getList();
+ method @Deprecated public void setInlineCountLimit(int);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
}
}
diff --git a/apex/media/framework/java/android/media/MediaParceledListSlice.java b/apex/media/framework/java/android/media/MediaParceledListSlice.java
index e1223f6..47ac193 100644
--- a/apex/media/framework/java/android/media/MediaParceledListSlice.java
+++ b/apex/media/framework/java/android/media/MediaParceledListSlice.java
@@ -17,7 +17,6 @@
package android.media;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,13 +31,16 @@
* Transfer a large list of Parcelable objects across an IPC. Splits into
* multiple transactions if needed.
*
- * @see BaseMediaParceledListSlice
- *
* TODO: Remove this from @SystemApi once all the MediaSession related classes are moved
* to apex (or ParceledListSlice moved to apex). This class is temporaily added to system API
* for moving classes step by step.
+ *
+ * @param <T> The type of the elements in the list.
+ * @see BaseMediaParceledListSlice
+ * @deprecated This is temporary marked as @SystemApi. Should be removed from the API surface.
* @hide
*/
+@Deprecated
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class MediaParceledListSlice<T extends Parcelable>
extends BaseMediaParceledListSlice<T> {
diff --git a/api/Android.bp b/api/Android.bp
index 490c980..e403082 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -64,6 +64,24 @@
}
genrule {
+ name: "frameworks-base-api-removed-merged.txt",
+ srcs: [
+ ":conscrypt.module.public.api{.public.removed-api.txt}",
+ ":framework-media{.public.removed-api.txt}",
+ ":framework-mediaprovider{.public.removed-api.txt}",
+ ":framework-permission{.public.removed-api.txt}",
+ ":framework-sdkextensions{.public.removed-api.txt}",
+ ":framework-statsd{.public.removed-api.txt}",
+ ":framework-tethering{.public.removed-api.txt}",
+ ":framework-wifi{.public.removed-api.txt}",
+ ":non-updatable-removed.txt",
+ ],
+ out: ["removed.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
name: "frameworks-base-api-system-current-merged.txt",
srcs: [
":framework-graphics{.system.api.txt}",
@@ -82,6 +100,23 @@
}
genrule {
+ name: "frameworks-base-api-system-removed-merged.txt",
+ srcs: [
+ ":framework-media{.system.removed-api.txt}",
+ ":framework-mediaprovider{.system.removed-api.txt}",
+ ":framework-permission{.system.removed-api.txt}",
+ ":framework-sdkextensions{.system.removed-api.txt}",
+ ":framework-statsd{.system.removed-api.txt}",
+ ":framework-tethering{.system.removed-api.txt}",
+ ":framework-wifi{.system.removed-api.txt}",
+ ":non-updatable-system-removed.txt",
+ ],
+ out: ["system-removed.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
name: "frameworks-base-api-module-lib-current-merged.txt",
srcs: [
":framework-graphics{.module-lib.api.txt}",
@@ -98,3 +133,20 @@
tools: ["metalava"],
cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
}
+
+genrule {
+ name: "frameworks-base-api-module-lib-removed-merged.txt",
+ srcs: [
+ ":framework-media{.module-lib.removed-api.txt}",
+ ":framework-mediaprovider{.module-lib.removed-api.txt}",
+ ":framework-permission{.module-lib.removed-api.txt}",
+ ":framework-sdkextensions{.module-lib.removed-api.txt}",
+ ":framework-statsd{.module-lib.removed-api.txt}",
+ ":framework-tethering{.module-lib.removed-api.txt}",
+ ":framework-wifi{.module-lib.removed-api.txt}",
+ ":non-updatable-module-lib-removed.txt",
+ ],
+ out: ["module-lib-removed.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
diff --git a/api/current.txt b/api/current.txt
index 8776d2d..94e90a7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@
field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+ field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -129,6 +130,7 @@
field public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
field public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+ field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
@@ -644,10 +646,10 @@
field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
- field public static final int fontProviderAuthority = 16844112; // 0x1010550
- field public static final int fontProviderCerts = 16844125; // 0x101055d
- field public static final int fontProviderPackage = 16844119; // 0x1010557
- field public static final int fontProviderQuery = 16844113; // 0x1010551
+ field @Deprecated public static final int fontProviderAuthority = 16844112; // 0x1010550
+ field @Deprecated public static final int fontProviderCerts = 16844125; // 0x101055d
+ field @Deprecated public static final int fontProviderPackage = 16844119; // 0x1010557
+ field @Deprecated public static final int fontProviderQuery = 16844113; // 0x1010551
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontVariationSettings = 16844144; // 0x1010570
field public static final int fontWeight = 16844083; // 0x1010533
@@ -12235,6 +12237,7 @@
field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
+ field public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 8; // 0x8
field public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 2; // 0x2
field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1
field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4
@@ -12344,6 +12347,7 @@
field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4
field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10
field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
+ field public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 32; // 0x20
field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8
field public static final int PROTECTION_DANGEROUS = 1; // 0x1
field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
@@ -31607,6 +31611,7 @@
method public boolean isEasyConnectSupported();
method public boolean isEnhancedOpenSupported();
method public boolean isEnhancedPowerReportingSupported();
+ method public boolean isMultiStaConcurrencySupported();
method public boolean isP2pSupported();
method public boolean isPreferredNetworkOffloadSupported();
method @Deprecated public boolean isScanAlwaysAvailable();
@@ -36670,7 +36675,7 @@
method public int dataCapacity();
method public int dataPosition();
method public int dataSize();
- method public void enforceInterface(String);
+ method public void enforceInterface(@NonNull String);
method public boolean hasFileDescriptors();
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
@@ -36741,7 +36746,7 @@
method public void writeFloatArray(@Nullable float[]);
method public void writeInt(int);
method public void writeIntArray(@Nullable int[]);
- method public void writeInterfaceToken(String);
+ method public void writeInterfaceToken(@NonNull String);
method public void writeList(@Nullable java.util.List);
method public void writeLong(long);
method public void writeLongArray(@Nullable long[]);
@@ -40185,62 +40190,62 @@
method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
}
- public final class FontRequest {
- ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String);
- ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
- method public java.util.List<java.util.List<byte[]>> getCertificates();
- method public String getProviderAuthority();
- method public String getProviderPackage();
- method public String getQuery();
+ @Deprecated public final class FontRequest {
+ ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String);
+ ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
+ method @Deprecated public java.util.List<java.util.List<byte[]>> getCertificates();
+ method @Deprecated public String getProviderAuthority();
+ method @Deprecated public String getProviderPackage();
+ method @Deprecated public String getQuery();
}
- public class FontsContract {
- method public static android.graphics.Typeface buildTypeface(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontInfo[]);
- method @NonNull public static android.provider.FontsContract.FontFamilyResult fetchFonts(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
- method public static void requestFonts(@NonNull android.content.Context, @NonNull android.provider.FontRequest, @NonNull android.os.Handler, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontRequestCallback);
+ @Deprecated public class FontsContract {
+ method @Deprecated public static android.graphics.Typeface buildTypeface(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontInfo[]);
+ method @Deprecated @NonNull public static android.provider.FontsContract.FontFamilyResult fetchFonts(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public static void requestFonts(@NonNull android.content.Context, @NonNull android.provider.FontRequest, @NonNull android.os.Handler, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontRequestCallback);
}
- public static final class FontsContract.Columns implements android.provider.BaseColumns {
- field public static final String FILE_ID = "file_id";
- field public static final String ITALIC = "font_italic";
- field public static final String RESULT_CODE = "result_code";
- field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
- field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
- field public static final int RESULT_CODE_OK = 0; // 0x0
- field public static final String TTC_INDEX = "font_ttc_index";
- field public static final String VARIATION_SETTINGS = "font_variation_settings";
- field public static final String WEIGHT = "font_weight";
+ @Deprecated public static final class FontsContract.Columns implements android.provider.BaseColumns {
+ field @Deprecated public static final String FILE_ID = "file_id";
+ field @Deprecated public static final String ITALIC = "font_italic";
+ field @Deprecated public static final String RESULT_CODE = "result_code";
+ field @Deprecated public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field @Deprecated public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field @Deprecated public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field @Deprecated public static final int RESULT_CODE_OK = 0; // 0x0
+ field @Deprecated public static final String TTC_INDEX = "font_ttc_index";
+ field @Deprecated public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field @Deprecated public static final String WEIGHT = "font_weight";
}
- public static class FontsContract.FontFamilyResult {
- method @NonNull public android.provider.FontsContract.FontInfo[] getFonts();
- method public int getStatusCode();
- field public static final int STATUS_OK = 0; // 0x0
- field public static final int STATUS_REJECTED = 3; // 0x3
- field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
- field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ @Deprecated public static class FontsContract.FontFamilyResult {
+ method @Deprecated @NonNull public android.provider.FontsContract.FontInfo[] getFonts();
+ method @Deprecated public int getStatusCode();
+ field @Deprecated public static final int STATUS_OK = 0; // 0x0
+ field @Deprecated public static final int STATUS_REJECTED = 3; // 0x3
+ field @Deprecated public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field @Deprecated public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
}
- public static class FontsContract.FontInfo {
- method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
- method public int getResultCode();
- method @IntRange(from=0) public int getTtcIndex();
- method @NonNull public android.net.Uri getUri();
- method @IntRange(from=1, to=1000) public int getWeight();
- method public boolean isItalic();
+ @Deprecated public static class FontsContract.FontInfo {
+ method @Deprecated @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
+ method @Deprecated public int getResultCode();
+ method @Deprecated @IntRange(from=0) public int getTtcIndex();
+ method @Deprecated @NonNull public android.net.Uri getUri();
+ method @Deprecated @IntRange(from=1, to=1000) public int getWeight();
+ method @Deprecated public boolean isItalic();
}
- public static class FontsContract.FontRequestCallback {
- ctor public FontsContract.FontRequestCallback();
- method public void onTypefaceRequestFailed(int);
- method public void onTypefaceRetrieved(android.graphics.Typeface);
- field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
- field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
- field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
- field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
- field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ @Deprecated public static class FontsContract.FontRequestCallback {
+ ctor @Deprecated public FontsContract.FontRequestCallback();
+ method @Deprecated public void onTypefaceRequestFailed(int);
+ method @Deprecated public void onTypefaceRetrieved(android.graphics.Typeface);
+ field @Deprecated public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field @Deprecated public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field @Deprecated public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field @Deprecated public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field @Deprecated public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field @Deprecated public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
}
@Deprecated public final class LiveFolders implements android.provider.BaseColumns {
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 4a7c121..19f348c 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -19,7 +19,7 @@
package android.app.role {
public final class RoleManager {
- method @Nullable public String getDefaultSmsPackage(int);
+ method @Nullable public String getSmsRoleHolder(int);
}
}
@@ -53,14 +53,14 @@
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
- public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
- ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
- method public int describeContents();
- method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
- method public java.util.List<T> getList();
- method public void setInlineCountLimit(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
+ @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
+ ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
+ method @Deprecated public java.util.List<T> getList();
+ method @Deprecated public void setInlineCountLimit(int);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 949a54a..f2ec297 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -95,6 +95,7 @@
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
+ field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
@@ -125,6 +126,7 @@
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+ field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -305,6 +307,7 @@
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
+ field public static final int config_systemVideoCall = 17039401; // 0x1040029
}
public static final class R.style {
@@ -1389,6 +1392,57 @@
}
+package android.app.time {
+
+ public final class TimeManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void removeTimeZoneDetectorListener(@NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public boolean updateTimeZoneConfiguration(@NonNull android.app.time.TimeZoneConfiguration);
+ }
+
+ @java.lang.FunctionalInterface public static interface TimeManager.TimeZoneDetectorListener {
+ method public void onChange();
+ }
+
+ public final class TimeZoneCapabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConfigureAutoDetectionEnabledCapability();
+ method public int getConfigureGeoDetectionEnabledCapability();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
+ field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
+ field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
+ field public static final int CAPABILITY_POSSESSED = 40; // 0x28
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
+ }
+
+ public final class TimeZoneCapabilitiesAndConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.app.time.TimeZoneCapabilities getCapabilities();
+ method @NonNull public android.app.time.TimeZoneConfiguration getConfiguration();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilitiesAndConfig> CREATOR;
+ }
+
+ public final class TimeZoneConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isAutoDetectionEnabled();
+ method public boolean isGeoDetectionEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneConfiguration> CREATOR;
+ }
+
+ public static final class TimeZoneConfiguration.Builder {
+ ctor public TimeZoneConfiguration.Builder();
+ ctor public TimeZoneConfiguration.Builder(@NonNull android.app.time.TimeZoneConfiguration);
+ method @NonNull public android.app.time.TimeZoneConfiguration build();
+ method @NonNull public android.app.time.TimeZoneConfiguration.Builder setAutoDetectionEnabled(boolean);
+ method @NonNull public android.app.time.TimeZoneConfiguration.Builder setGeoDetectionEnabled(boolean);
+ }
+
+}
+
package android.app.usage {
public final class CacheQuotaHint implements android.os.Parcelable {
@@ -2157,6 +2211,7 @@
field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
+ field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
@@ -7565,10 +7620,12 @@
public final class WifiNetworkSuggestion implements android.os.Parcelable {
method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
+ method public boolean isOemPaid();
}
public static final class WifiNetworkSuggestion.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean);
}
public class WifiScanner {
@@ -10718,16 +10775,12 @@
method public int getTimeoutSeconds();
method public boolean isEnabled();
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
- field public static final int ERROR_FDN_CHECK_FAILURE = 2; // 0x2
- field public static final int ERROR_NOT_SUPPORTED = 3; // 0x3
- field public static final int ERROR_UNKNOWN = 1; // 0x1
field public static final int REASON_ALL = 4; // 0x4
field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
field public static final int REASON_BUSY = 1; // 0x1
field public static final int REASON_NOT_REACHABLE = 3; // 0x3
field public static final int REASON_NO_REPLY = 2; // 0x2
field public static final int REASON_UNCONDITIONAL = 0; // 0x0
- field public static final int SUCCESS = 0; // 0x0
}
public final class CallQuality implements android.os.Parcelable {
@@ -11413,6 +11466,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
@@ -11470,7 +11524,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingStatus(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
@@ -11569,6 +11623,10 @@
public static interface TelephonyManager.CallForwardingInfoCallback {
method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo);
method public void onError(int);
+ field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 2; // 0x2
+ field public static final int RESULT_ERROR_NOT_SUPPORTED = 3; // 0x3
+ field public static final int RESULT_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 0; // 0x0
}
public final class UiccAccessRule implements android.os.Parcelable {
@@ -12960,11 +13018,12 @@
}
public interface PacProcessor {
+ method @NonNull public static android.webkit.PacProcessor createInstance();
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
+ method public default void setNetwork(@Nullable android.net.Network);
method public boolean setProxyScript(@NonNull String);
}
@@ -13100,11 +13159,11 @@
}
public interface WebViewFactoryProvider {
+ method @NonNull public default android.webkit.PacProcessor createPacProcessor();
method public android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/api/test-current.txt b/api/test-current.txt
index 4c2aa5a..576cbacb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -45,6 +45,7 @@
field public static final int config_defaultDialer = 17039395; // 0x1040023
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
+ field public static final int config_systemVideoCall = 17039401; // 0x1040029
}
}
@@ -767,10 +768,10 @@
method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Nullable public String getDefaultSmsPackage(int);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
+ method @Nullable public String getSmsRoleHolder(int);
method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
@@ -1037,6 +1038,7 @@
field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
+ field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index cb65482..bda9e24 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -38,7 +38,6 @@
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
import "frameworks/base/core/proto/android/server/enums.proto";
-import "frameworks/base/core/proto/android/stats/hdmi/enums.proto";
import "frameworks/base/core/proto/android/server/job/enums.proto";
import "frameworks/base/core/proto/android/server/location/enums.proto";
import "frameworks/base/core/proto/android/service/procstats_enum.proto";
@@ -51,6 +50,7 @@
import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
import "frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto";
import "frameworks/base/core/proto/android/stats/enums.proto";
+import "frameworks/base/core/proto/android/stats/hdmi/enums.proto";
import "frameworks/base/core/proto/android/stats/intelligence/enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
import "frameworks/base/core/proto/android/stats/location/location_enums.proto";
@@ -3777,6 +3777,7 @@
LAUNCHER = 1;
NOTIFICATION = 2;
LOCKSCREEN = 3;
+ RECENTS_ANIMATION = 4;
}
// The type of the startup source.
optional SourceType source_type = 16;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a61159a..85cb120 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1910,6 +1910,8 @@
public static final int TYPE_NOTIFICATION = 2;
/** Launched from lockscreen, including notification while the device is locked. */
public static final int TYPE_LOCKSCREEN = 3;
+ /** Launched from recents gesture handler. */
+ public static final int TYPE_RECENTS_ANIMATION = 4;
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
TYPE_LAUNCHER,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1a4db4e..1995128 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -25,7 +25,6 @@
import android.app.IApplicationThread;
import android.app.IActivityController;
import android.app.IAppTask;
-import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
import android.app.IServiceConnection;
@@ -70,7 +69,6 @@
import android.os.StrictMode;
import android.os.WorkSource;
import android.service.voice.IVoiceInteractionSession;
-import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
@@ -470,11 +468,6 @@
@UnsupportedAppUsage
boolean isInLockTaskMode();
@UnsupportedAppUsage
- void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
- in IRecentsAnimationRunner recentsAnimationRunner);
- @UnsupportedAppUsage
- void cancelRecentsAnimation(boolean restoreHomeStackPosition);
- @UnsupportedAppUsage
int startActivityFromRecents(int taskId, in Bundle options);
@UnsupportedAppUsage
void startSystemLockTaskMode(int taskId);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index e21ef8e..ddf2dc50 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -123,7 +123,7 @@
in ProfilerInfo profilerInfo, in Bundle options, int userId);
int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
- void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
+ void startRecentsActivity(in Intent intent, in long eventTime,
in IRecentsAnimationRunner recentsAnimationRunner);
int startActivityFromRecents(int taskId, in Bundle options);
int startActivityAsCaller(in IApplicationThread caller, in String callingPackage,
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index df53f98..32252a3f 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -326,6 +326,16 @@
out.writeBoolean(mAutoEnterEnabled);
}
+ @Override
+ public String toString() {
+ return "PictureInPictureParams("
+ + " aspectRatio=" + getAspectRatioRational()
+ + " sourceRectHint=" + getSourceRectHint()
+ + " hasSetActions=" + hasSetActions()
+ + " isAutoPipEnabled=" + isAutoEnterEnabled()
+ + ")";
+ }
+
public static final @android.annotation.NonNull Creator<PictureInPictureParams> CREATOR =
new Creator<PictureInPictureParams>() {
public PictureInPictureParams createFromParcel(Parcel in) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d50cdee..9100d57 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -33,6 +33,7 @@
import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
import android.app.slice.SliceManager;
+import android.app.time.TimeManager;
import android.app.timedetector.TimeDetector;
import android.app.timedetector.TimeDetectorImpl;
import android.app.timezone.RulesManager;
@@ -1218,6 +1219,14 @@
return new TimeZoneDetectorImpl();
}});
+ registerService(Context.TIME_MANAGER, TimeManager.class,
+ new CachedServiceFetcher<TimeManager>() {
+ @Override
+ public TimeManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new TimeManager();
+ }});
+
registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
new CachedServiceFetcher<PermissionManager>() {
@Override
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index a2f4414..3cc7f1e 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -55,14 +55,6 @@
static final String TAG = "DeviceAdminInfo";
/**
- * A type of policy that this device admin can use: profile owner on an organization-owned
- * device.
- *
- * @hide
- */
- public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3;
-
- /**
* A type of policy that this device admin can use: device owner meta-policy
* for an admin that is designated as owner of the device.
*
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 26edba3..87e1df3 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -636,7 +636,7 @@
@Nullable
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
- public String getDefaultSmsPackage(@UserIdInt int userId) {
+ public String getSmsRoleHolder(@UserIdInt int userId) {
try {
return mService.getDefaultSmsPackage(userId);
} catch (RemoteException e) {
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl b/core/java/android/app/time/ITimeZoneDetectorListener.aidl
similarity index 84%
copy from core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
copy to core/java/android/app/time/ITimeZoneDetectorListener.aidl
index 62240ba..723ad59 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
+++ b/core/java/android/app/time/ITimeZoneDetectorListener.aidl
@@ -14,6 +14,9 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
-parcelable TimeZoneConfiguration;
+/** {@hide} */
+oneway interface ITimeZoneDetectorListener {
+ void onChange();
+}
\ No newline at end of file
diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING
new file mode 100644
index 0000000..951905b
--- /dev/null
+++ b/core/java/android/app/time/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.app.time."
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/app/time/TimeManager.java b/core/java/android/app/time/TimeManager.java
new file mode 100644
index 0000000..4796d8d
--- /dev/null
+++ b/core/java/android/app/time/TimeManager.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.time;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.app.timezonedetector.ITimeZoneDetectorService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * The interface through which system components can interact with time and time zone services.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.TIME_MANAGER)
+public final class TimeManager {
+ private static final String TAG = "time.TimeManager";
+ private static final boolean DEBUG = false;
+
+ private final Object mLock = new Object();
+ private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+ @GuardedBy("mLock")
+ private ITimeZoneDetectorListener mTimeZoneDetectorReceiver;
+
+ /**
+ * The registered listeners. The key is the actual listener that was registered, the value is a
+ * wrapper that ensures the listener is executed on the correct Executor.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<TimeZoneDetectorListener, TimeZoneDetectorListener> mTimeZoneDetectorListeners;
+
+ /** @hide */
+ public TimeManager() throws ServiceNotFoundException {
+ // TimeManager is an API over one or possibly more services. At least until there's an
+ // internal refactoring.
+ mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+ }
+
+ /**
+ * Returns the calling user's time zone capabilities and configuration.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+ @NonNull
+ public TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig() {
+ if (DEBUG) {
+ Log.d(TAG, "getTimeZoneCapabilities called");
+ }
+ try {
+ return mITimeZoneDetectorService.getCapabilitiesAndConfig();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Modifies the time zone detection configuration.
+ *
+ * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
+ * specific to the current user.
+ *
+ * <p>The ability to modify configuration settings can be subject to restrictions. For
+ * example, they may be determined by device hardware, general policy (i.e. only the primary
+ * user can set them), or by a managed device policy. Use {@link
+ * #getTimeZoneCapabilitiesAndConfig()} to obtain information at runtime about the user's
+ * capabilities.
+ *
+ * <p>Attempts to modify configuration settings with capabilities that are {@link
+ * TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
+ * TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
+ * will be returned. Modifying configuration settings with capabilities that are {@link
+ * TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
+ * TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
+ * TimeZoneCapabilities} for further details.
+ *
+ * <p>If the supplied configuration only has some values set, then only the specified settings
+ * will be updated (where the user's capabilities allow) and other settings will be left
+ * unchanged.
+ *
+ * @return {@code true} if all the configuration settings specified have been set to the
+ * new values, {@code false} if none have
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+ public boolean updateTimeZoneConfiguration(@NonNull TimeZoneConfiguration configuration) {
+ if (DEBUG) {
+ Log.d(TAG, "updateConfiguration called: " + configuration);
+ }
+ try {
+ return mITimeZoneDetectorService.updateConfiguration(configuration);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * An interface that can be used to listen for changes to the time zone detector behavior.
+ */
+ @FunctionalInterface
+ public interface TimeZoneDetectorListener {
+ /**
+ * Called when something about the time zone detector behavior on the device has changed.
+ * For example, this could be because the current user has switched, one of the global or
+ * user's settings been changed, or something that could affect a user's capabilities with
+ * respect to the time zone detector has changed. Because different users can have different
+ * configuration and capabilities, this method may be called when nothing has changed for
+ * the receiving user.
+ */
+ void onChange();
+ }
+
+ /**
+ * Registers a listener that will be informed when something about the time zone detector
+ * behavior changes.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+ public void addTimeZoneDetectorListener(@NonNull Executor executor,
+ @NonNull TimeZoneDetectorListener listener) {
+
+ if (DEBUG) {
+ Log.d(TAG, "addTimeZoneDetectorListener called: " + listener);
+ }
+ synchronized (mLock) {
+ if (mTimeZoneDetectorListeners == null) {
+ mTimeZoneDetectorListeners = new ArrayMap<>();
+ } else if (mTimeZoneDetectorListeners.containsKey(listener)) {
+ return;
+ }
+
+ if (mTimeZoneDetectorReceiver == null) {
+ ITimeZoneDetectorListener iListener = new ITimeZoneDetectorListener.Stub() {
+ @Override
+ public void onChange() {
+ notifyTimeZoneDetectorListeners();
+ }
+ };
+ mTimeZoneDetectorReceiver = iListener;
+ try {
+ mITimeZoneDetectorService.addListener(mTimeZoneDetectorReceiver);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ mTimeZoneDetectorListeners.put(listener, () -> executor.execute(listener::onChange));
+ }
+ }
+
+ private void notifyTimeZoneDetectorListeners() {
+ ArrayMap<TimeZoneDetectorListener, TimeZoneDetectorListener> timeZoneDetectorListeners;
+ synchronized (mLock) {
+ if (mTimeZoneDetectorListeners == null || mTimeZoneDetectorListeners.isEmpty()) {
+ return;
+ }
+ timeZoneDetectorListeners = new ArrayMap<>(mTimeZoneDetectorListeners);
+ }
+ int size = timeZoneDetectorListeners.size();
+ for (int i = 0; i < size; i++) {
+ timeZoneDetectorListeners.valueAt(i).onChange();
+ }
+ }
+
+ /**
+ * Removes a listener previously passed to
+ * {@link #addTimeZoneDetectorListener(Executor, TimeZoneDetectorListener)}
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+ public void removeTimeZoneDetectorListener(@NonNull TimeZoneDetectorListener listener) {
+ if (DEBUG) {
+ Log.d(TAG, "removeConfigurationListener called: " + listener);
+ }
+
+ synchronized (mLock) {
+ if (mTimeZoneDetectorListeners == null || mTimeZoneDetectorListeners.isEmpty()) {
+ return;
+ }
+ mTimeZoneDetectorListeners.remove(listener);
+
+ // If the last local listener has been removed, remove and discard the
+ // mTimeZoneDetectorReceiver.
+ if (mTimeZoneDetectorListeners.isEmpty()) {
+ try {
+ mITimeZoneDetectorService.removeListener(mTimeZoneDetectorReceiver);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ mTimeZoneDetectorReceiver = null;
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl b/core/java/android/app/time/TimeZoneCapabilities.aidl
similarity index 94%
rename from core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl
rename to core/java/android/app/time/TimeZoneCapabilities.aidl
index fede645..f744bf1 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl
+++ b/core/java/android/app/time/TimeZoneCapabilities.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
parcelable TimeZoneCapabilities;
diff --git a/core/java/android/app/time/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java
new file mode 100644
index 0000000..df89c28
--- /dev/null
+++ b/core/java/android/app/time/TimeZoneCapabilities.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.time;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Time zone-related capabilities for a user. A capability is the ability for the user to configure
+ * something or perform an action. This information is exposed so that system apps like SettingsUI
+ * can be dynamic, rather than hard-coding knowledge of when configuration or actions are applicable
+ * / available to the user.
+ *
+ * <p>Capabilities have states that users cannot change directly. They may influence some
+ * capabilities indirectly by agreeing to certain device-wide behaviors such as location sharing, or
+ * by changing the configuration. See the {@code CAPABILITY_} constants for details.
+ *
+ * <p>Actions have associated methods, see the documentation for each action for details.
+ *
+ * <p>For configuration settings capabilities, the associated settings value can be found via
+ * {@link TimeManager#getTimeZoneCapabilitiesAndConfig()} and may be changed using {@link
+ * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} (if the user's capabilities
+ * allow).
+ *
+ * <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TimeZoneCapabilities implements Parcelable {
+
+ /** @hide */
+ @IntDef({ CAPABILITY_NOT_SUPPORTED, CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_APPLICABLE,
+ CAPABILITY_POSSESSED })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CapabilityState {}
+
+ /**
+ * Indicates that a capability is not supported on this device, e.g. because of form factor or
+ * hardware. The associated UI should usually not be shown to the user.
+ */
+ public static final int CAPABILITY_NOT_SUPPORTED = 10;
+
+ /**
+ * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
+ * if the capability relates to the ability to modify settings the user is not able to.
+ * This could be because of the user's type (e.g. maybe it applies to the primary user only) or
+ * device policy. Depending on the capability, this could mean the associated UI
+ * should be hidden, or displayed but disabled.
+ */
+ public static final int CAPABILITY_NOT_ALLOWED = 20;
+
+ /**
+ * Indicates that a capability is possessed but not currently applicable, e.g. if the
+ * capability relates to the ability to modify settings, the user has the ability to modify
+ * it, but it is currently rendered irrelevant by other settings or other device state (flags,
+ * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
+ * ineffective) depending on requirements.
+ */
+ public static final int CAPABILITY_NOT_APPLICABLE = 30;
+
+ /** Indicates that a capability is possessed by the user. */
+ public static final int CAPABILITY_POSSESSED = 40;
+
+ public static final @NonNull Creator<TimeZoneCapabilities> CREATOR =
+ new Creator<TimeZoneCapabilities>() {
+ public TimeZoneCapabilities createFromParcel(Parcel in) {
+ return TimeZoneCapabilities.createFromParcel(in);
+ }
+
+ public TimeZoneCapabilities[] newArray(int size) {
+ return new TimeZoneCapabilities[size];
+ }
+ };
+
+ /**
+ * The user the capabilities are for. This is used for object equality and debugging but there
+ * is no accessor.
+ */
+ @NonNull private final UserHandle mUserHandle;
+ private final @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+ private final @CapabilityState int mConfigureGeoDetectionEnabledCapability;
+ private final @CapabilityState int mSuggestManualTimeZoneCapability;
+
+ private TimeZoneCapabilities(@NonNull Builder builder) {
+ this.mUserHandle = Objects.requireNonNull(builder.mUserHandle);
+ this.mConfigureAutoDetectionEnabledCapability =
+ builder.mConfigureAutoDetectionEnabledCapability;
+ this.mConfigureGeoDetectionEnabledCapability =
+ builder.mConfigureGeoDetectionEnabledCapability;
+ this.mSuggestManualTimeZoneCapability = builder.mSuggestManualTimeZoneCapability;
+ }
+
+ @NonNull
+ private static TimeZoneCapabilities createFromParcel(Parcel in) {
+ UserHandle userHandle = UserHandle.readFromParcel(in);
+ return new TimeZoneCapabilities.Builder(userHandle)
+ .setConfigureAutoDetectionEnabledCapability(in.readInt())
+ .setConfigureGeoDetectionEnabledCapability(in.readInt())
+ .setSuggestManualTimeZoneCapability(in.readInt())
+ .build();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ UserHandle.writeToParcel(mUserHandle, dest);
+ dest.writeInt(mConfigureAutoDetectionEnabledCapability);
+ dest.writeInt(mConfigureGeoDetectionEnabledCapability);
+ dest.writeInt(mSuggestManualTimeZoneCapability);
+ }
+
+ /**
+ * Returns the capability state associated with the user's ability to modify the automatic time
+ * zone detection setting. The setting can be updated via {@link
+ * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}.
+ */
+ @CapabilityState
+ public int getConfigureAutoDetectionEnabledCapability() {
+ return mConfigureAutoDetectionEnabledCapability;
+ }
+
+ /**
+ * Returns the capability state associated with the user's ability to modify the geolocation
+ * detection setting. The setting can be updated via {@link
+ * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}.
+ */
+ @CapabilityState
+ public int getConfigureGeoDetectionEnabledCapability() {
+ return mConfigureGeoDetectionEnabledCapability;
+ }
+
+ /**
+ * Returns the capability state associated with the user's ability to manually set the time zone
+ * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
+ *
+ * <p>The suggestion will be ignored in all cases unless the value is {@link
+ * #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
+ *
+ * @hide
+ */
+ @CapabilityState
+ public int getSuggestManualTimeZoneCapability() {
+ return mSuggestManualTimeZoneCapability;
+ }
+
+ /**
+ * Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of
+ * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is
+ * returned. If the capabilities do not permit one or more of the requested changes then {@code
+ * null} is returned.
+ *
+ * @hide
+ */
+ @Nullable
+ public TimeZoneConfiguration tryApplyConfigChanges(
+ @NonNull TimeZoneConfiguration config,
+ @NonNull TimeZoneConfiguration requestedChanges) {
+ TimeZoneConfiguration.Builder newConfigBuilder =
+ new TimeZoneConfiguration.Builder(config);
+ if (requestedChanges.hasIsAutoDetectionEnabled()) {
+ if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
+ }
+
+ if (requestedChanges.hasIsGeoDetectionEnabled()) {
+ if (this.getConfigureGeoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
+ }
+
+ return newConfigBuilder.build();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TimeZoneCapabilities that = (TimeZoneCapabilities) o;
+ return mUserHandle.equals(that.mUserHandle)
+ && mConfigureAutoDetectionEnabledCapability
+ == that.mConfigureAutoDetectionEnabledCapability
+ && mConfigureGeoDetectionEnabledCapability
+ == that.mConfigureGeoDetectionEnabledCapability
+ && mSuggestManualTimeZoneCapability == that.mSuggestManualTimeZoneCapability;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability,
+ mConfigureGeoDetectionEnabledCapability, mSuggestManualTimeZoneCapability);
+ }
+
+ @Override
+ public String toString() {
+ return "TimeZoneDetectorCapabilities{"
+ + "mUserHandle=" + mUserHandle
+ + ", mConfigureAutoDetectionEnabledCapability="
+ + mConfigureAutoDetectionEnabledCapability
+ + ", mConfigureGeoDetectionEnabledCapability="
+ + mConfigureGeoDetectionEnabledCapability
+ + ", mSuggestManualTimeZoneCapability=" + mSuggestManualTimeZoneCapability
+ + '}';
+ }
+
+ /** @hide */
+ public static class Builder {
+
+ @NonNull private UserHandle mUserHandle;
+ private @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+ private @CapabilityState int mConfigureGeoDetectionEnabledCapability;
+ private @CapabilityState int mSuggestManualTimeZoneCapability;
+
+ public Builder(@NonNull UserHandle userHandle) {
+ mUserHandle = Objects.requireNonNull(userHandle);
+ }
+
+ /** Sets the state for the automatic time zone detection enabled config. */
+ public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) {
+ this.mConfigureAutoDetectionEnabledCapability = value;
+ return this;
+ }
+
+ /** Sets the state for the geolocation time zone detection enabled config. */
+ public Builder setConfigureGeoDetectionEnabledCapability(@CapabilityState int value) {
+ this.mConfigureGeoDetectionEnabledCapability = value;
+ return this;
+ }
+
+ /** Sets the state for the suggestManualTimeZone action. */
+ public Builder setSuggestManualTimeZoneCapability(@CapabilityState int value) {
+ this.mSuggestManualTimeZoneCapability = value;
+ return this;
+ }
+
+ /** Returns the {@link TimeZoneCapabilities}. */
+ @NonNull
+ public TimeZoneCapabilities build() {
+ verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability,
+ "configureAutoDetectionEnabledCapability");
+ verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability,
+ "configureGeoDetectionEnabledCapability");
+ verifyCapabilitySet(mSuggestManualTimeZoneCapability,
+ "suggestManualTimeZoneCapability");
+ return new TimeZoneCapabilities(this);
+ }
+
+ private void verifyCapabilitySet(int value, String name) {
+ if (value == 0) {
+ throw new IllegalStateException(name + " not set");
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl
similarity index 89%
copy from core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl
copy to core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl
index fede645..d7b6b58 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl
+++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
-parcelable TimeZoneCapabilities;
+parcelable TimeZoneCapabilitiesAndConfig;
diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
new file mode 100644
index 0000000..b339e53
--- /dev/null
+++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.time;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A pair containing a user's {@link TimeZoneCapabilities} and {@link TimeZoneConfiguration}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
+
+ public static final @NonNull Creator<TimeZoneCapabilitiesAndConfig> CREATOR =
+ new Creator<TimeZoneCapabilitiesAndConfig>() {
+ public TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
+ return TimeZoneCapabilitiesAndConfig.createFromParcel(in);
+ }
+
+ public TimeZoneCapabilitiesAndConfig[] newArray(int size) {
+ return new TimeZoneCapabilitiesAndConfig[size];
+ }
+ };
+
+
+ @NonNull private final TimeZoneCapabilities mCapabilities;
+ @NonNull private final TimeZoneConfiguration mConfiguration;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
+ public TimeZoneCapabilitiesAndConfig(
+ @NonNull TimeZoneCapabilities capabilities,
+ @NonNull TimeZoneConfiguration configuration) {
+ this.mCapabilities = Objects.requireNonNull(capabilities);
+ this.mConfiguration = Objects.requireNonNull(configuration);
+ }
+
+ @NonNull
+ private static TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
+ TimeZoneCapabilities capabilities = in.readParcelable(null);
+ TimeZoneConfiguration configuration = in.readParcelable(null);
+ return new TimeZoneCapabilitiesAndConfig(capabilities, configuration);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mCapabilities, flags);
+ dest.writeParcelable(mConfiguration, flags);
+ }
+
+ /**
+ * Returns the user's time zone behavior capabilities.
+ */
+ @NonNull
+ public TimeZoneCapabilities getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Returns the user's time zone behavior configuration.
+ */
+ @NonNull
+ public TimeZoneConfiguration getConfiguration() {
+ return mConfiguration;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TimeZoneCapabilitiesAndConfig that = (TimeZoneCapabilitiesAndConfig) o;
+ return mCapabilities.equals(that.mCapabilities)
+ && mConfiguration.equals(that.mConfiguration);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCapabilities, mConfiguration);
+ }
+
+ @Override
+ public String toString() {
+ return "TimeZoneDetectorCapabilitiesAndConfig{"
+ + "mCapabilities=" + mCapabilities
+ + ", mConfiguration=" + mConfiguration
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl b/core/java/android/app/time/TimeZoneConfiguration.aidl
similarity index 94%
rename from core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
rename to core/java/android/app/time/TimeZoneConfiguration.aidl
index 62240ba..8e85929 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
+++ b/core/java/android/app/time/TimeZoneConfiguration.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
parcelable TimeZoneConfiguration;
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/time/TimeZoneConfiguration.java
similarity index 65%
rename from core/java/android/app/timezonedetector/TimeZoneConfiguration.java
rename to core/java/android/app/time/TimeZoneConfiguration.java
index e879091..c0a0c21 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
+++ b/core/java/android/app/time/TimeZoneConfiguration.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
import android.annotation.NonNull;
import android.annotation.StringDef;
-import android.annotation.UserIdInt;
+import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,15 +36,13 @@
* several settings, the device behavior may not be directly affected by the setting value.
*
* <p>Settings can be left absent when updating configuration via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be
+ * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} and those settings will not be
* changed. Not all configuration settings can be modified by all users: see {@link
- * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details.
- *
- * <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence
- * of individual settings.
+ * TimeManager#getTimeZoneCapabilitiesAndConfig()} and {@link TimeZoneCapabilities} for details.
*
* @hide
*/
+@SystemApi
public final class TimeZoneConfiguration implements Parcelable {
public static final @NonNull Creator<TimeZoneConfiguration> CREATOR =
@@ -58,53 +56,48 @@
}
};
- /** All configuration properties */
+ /**
+ * All configuration properties
+ *
+ * @hide
+ */
@StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED })
@Retention(RetentionPolicy.SOURCE)
@interface Setting {}
/** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */
@Setting
- public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+ private static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
/** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
@Setting
- public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
+ private static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
- private final @UserIdInt int mUserId;
@NonNull private final Bundle mBundle;
private TimeZoneConfiguration(Builder builder) {
- this.mUserId = builder.mUserId;
this.mBundle = Objects.requireNonNull(builder.mBundle);
}
private static TimeZoneConfiguration createFromParcel(Parcel in) {
- return new TimeZoneConfiguration.Builder(in.readInt())
+ return new TimeZoneConfiguration.Builder()
.setPropertyBundleInternal(in.readBundle())
.build();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mUserId);
dest.writeBundle(mBundle);
}
- /** Returns the ID of the user this configuration is associated with. */
- public @UserIdInt int getUserId() {
- return mUserId;
- }
-
- /** Returns {@code true} if all known settings are present. */
+ /**
+ * Returns {@code true} if all known settings are present.
+ *
+ * @hide
+ */
public boolean isComplete() {
- return hasSetting(SETTING_AUTO_DETECTION_ENABLED)
- && hasSetting(SETTING_GEO_DETECTION_ENABLED);
- }
-
- /** Returns true if the specified setting is set. */
- public boolean hasSetting(@Setting String setting) {
- return mBundle.containsKey(setting);
+ return hasIsAutoDetectionEnabled()
+ && hasIsGeoDetectionEnabled();
}
/**
@@ -112,9 +105,10 @@
* controls whether a device will attempt to determine the time zone automatically using
* contextual information if the device supports auto detection.
*
- * <p>This setting is global and can be updated by some users.
+ * <p>See {@link TimeZoneCapabilities#getConfigureAutoDetectionEnabledCapability()} for how to
+ * tell if the setting is meaningful for the current user at this time.
*
- * @throws IllegalStateException if the setting has not been set
+ * @throws IllegalStateException if the setting is not present
*/
public boolean isAutoDetectionEnabled() {
enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
@@ -122,21 +116,39 @@
}
/**
+ * Returns {@code true} if the {@link #isAutoDetectionEnabled()} setting is present.
+ *
+ * @hide
+ */
+ public boolean hasIsAutoDetectionEnabled() {
+ return mBundle.containsKey(SETTING_AUTO_DETECTION_ENABLED);
+ }
+
+ /**
* Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This
- * controls whether a device can use geolocation to determine time zone. Only used when
- * {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their
- * location to be used.
+ * controls whether the device can use geolocation to determine time zone. This value may only
+ * be used by Android under some circumstances. For example, it is not used when
+ * {@link #isGeoDetectionEnabled()} is {@code false}.
*
- * <p>This setting is user-scoped and can be updated by some users.
- * See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}.
+ * <p>See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabledCapability()} for how to
+ * tell if the setting is meaningful for the current user at this time.
*
- * @throws IllegalStateException if the setting has not been set
+ * @throws IllegalStateException if the setting is not present
*/
public boolean isGeoDetectionEnabled() {
enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED);
return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED);
}
+ /**
+ * Returns {@code true} if the {@link #isGeoDetectionEnabled()} setting is present.
+ *
+ * @hide
+ */
+ public boolean hasIsGeoDetectionEnabled() {
+ return mBundle.containsKey(SETTING_GEO_DETECTION_ENABLED);
+ }
+
@Override
public int describeContents() {
return 0;
@@ -151,20 +163,18 @@
return false;
}
TimeZoneConfiguration that = (TimeZoneConfiguration) o;
- return mUserId == that.mUserId
- && mBundle.kindofEquals(that.mBundle);
+ return mBundle.kindofEquals(that.mBundle);
}
@Override
public int hashCode() {
- return Objects.hash(mUserId, mBundle);
+ return Objects.hash(mBundle);
}
@Override
public String toString() {
return "TimeZoneConfiguration{"
- + "mUserId=" + mUserId
- + ", mBundle=" + mBundle
+ + "mBundle=" + mBundle
+ '}';
}
@@ -174,43 +184,43 @@
}
}
- /** @hide */
- public static class Builder {
+ /**
+ * A builder for {@link TimeZoneConfiguration} objects.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
- private final @UserIdInt int mUserId;
private final Bundle mBundle = new Bundle();
/**
- * Creates a new Builder for a userId with no settings held.
+ * Creates a new Builder with no settings held.
*/
- public Builder(@UserIdInt int userId) {
- mUserId = userId;
+ public Builder() {
}
/**
- * Creates a new Builder by copying the user ID and settings from an existing instance.
+ * Creates a new Builder by copying the settings from an existing instance.
*/
- public Builder(TimeZoneConfiguration toCopy) {
- this.mUserId = toCopy.mUserId;
+ public Builder(@NonNull TimeZoneConfiguration toCopy) {
mergeProperties(toCopy);
}
/**
* Merges {@code other} settings into this instances, replacing existing values in this
* where the settings appear in both.
+ *
+ * @hide
*/
- public Builder mergeProperties(TimeZoneConfiguration other) {
- if (mUserId != other.mUserId) {
- throw new IllegalArgumentException(
- "Cannot merge configurations for different user IDs."
- + " this.mUserId=" + this.mUserId
- + ", other.mUserId=" + other.mUserId);
- }
+ @NonNull
+ public Builder mergeProperties(@NonNull TimeZoneConfiguration other) {
this.mBundle.putAll(other.mBundle);
return this;
}
- Builder setPropertyBundleInternal(Bundle bundle) {
+ @NonNull
+ Builder setPropertyBundleInternal(@NonNull Bundle bundle) {
this.mBundle.putAll(bundle);
return this;
}
@@ -218,6 +228,7 @@
/**
* Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting.
*/
+ @NonNull
public Builder setAutoDetectionEnabled(boolean enabled) {
this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
return this;
@@ -226,6 +237,7 @@
/**
* Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting.
*/
+ @NonNull
public Builder setGeoDetectionEnabled(boolean enabled) {
this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled);
return this;
diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
deleted file mode 100644
index 6d0fe72..0000000
--- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezonedetector;
-
-import android.app.timezonedetector.TimeZoneConfiguration;
-
-/** {@hide} */
-oneway interface ITimeZoneConfigurationListener {
- void onChange();
-}
\ No newline at end of file
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
index 4f7e1f6..af0389a 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -16,11 +16,11 @@
package android.app.timezonedetector;
-import android.app.timezonedetector.ITimeZoneConfigurationListener;
+import android.app.time.ITimeZoneDetectorListener;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
-import android.app.timezonedetector.TimeZoneConfiguration;
/**
* System private API to communicate with time zone detector service.
@@ -35,9 +35,9 @@
* {@hide}
*/
interface ITimeZoneDetectorService {
- TimeZoneCapabilities getCapabilities();
- void addConfigurationListener(ITimeZoneConfigurationListener listener);
- void removeConfigurationListener(ITimeZoneConfigurationListener listener);
+ TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig();
+ void addListener(ITimeZoneDetectorListener listener);
+ void removeListener(ITimeZoneDetectorListener listener);
boolean updateConfiguration(in TimeZoneConfiguration configuration);
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
deleted file mode 100644
index 09fffe9..0000000
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezonedetector;
-
-import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED;
-import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Time zone-related capabilities for a user. A capability is the ability for the user to configure
- * something or perform an action. This information is exposed so that system apps like SettingsUI
- * can be dynamic, rather than hard-coding knowledge of when configuration or actions are applicable
- * / available to the user.
- *
- * <p>Capabilities have states that users cannot change directly. They may influence some
- * capabilities indirectly by agreeing to certain device-wide behaviors such as location sharing, or
- * by changing the configuration. See the {@code CAPABILITY_} constants for details.
- *
- * <p>Actions have associated methods, see the documentation for each action for details.
- *
- * <p>For configuration settings capabilities, the associated settings value can be found via
- * {@link #getConfiguration()} and may be changed using {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow).
- *
- * <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
- *
- * @hide
- */
-public final class TimeZoneCapabilities implements Parcelable {
-
- @IntDef({ CAPABILITY_NOT_SUPPORTED, CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_APPLICABLE,
- CAPABILITY_POSSESSED })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CapabilityState {}
-
- /**
- * Indicates that a capability is not supported on this device, e.g. because of form factor or
- * hardware. The associated UI should usually not be shown to the user.
- */
- public static final int CAPABILITY_NOT_SUPPORTED = 10;
-
- /**
- * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
- * if the capability relates to the ability to modify settings the user is not able to.
- * This could be because of the user's type (e.g. maybe it applies to the primary user only) or
- * device policy. Depending on the capability, this could mean the associated UI
- * should be hidden, or displayed but disabled.
- */
- public static final int CAPABILITY_NOT_ALLOWED = 20;
-
- /**
- * Indicates that a capability is possessed but not currently applicable, e.g. if the
- * capability relates to the ability to modify settings, the user has the ability to modify
- * it, but it is currently rendered irrelevant by other settings or other device state (flags,
- * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
- * ineffective) depending on requirements.
- */
- public static final int CAPABILITY_NOT_APPLICABLE = 30;
-
- /** Indicates that a capability is possessed by the user. */
- public static final int CAPABILITY_POSSESSED = 40;
-
- public static final @NonNull Creator<TimeZoneCapabilities> CREATOR =
- new Creator<TimeZoneCapabilities>() {
- public TimeZoneCapabilities createFromParcel(Parcel in) {
- return TimeZoneCapabilities.createFromParcel(in);
- }
-
- public TimeZoneCapabilities[] newArray(int size) {
- return new TimeZoneCapabilities[size];
- }
- };
-
-
- @NonNull private final TimeZoneConfiguration mConfiguration;
- private final @CapabilityState int mConfigureAutoDetectionEnabled;
- private final @CapabilityState int mConfigureGeoDetectionEnabled;
- private final @CapabilityState int mSuggestManualTimeZone;
-
- private TimeZoneCapabilities(@NonNull Builder builder) {
- this.mConfiguration = Objects.requireNonNull(builder.mConfiguration);
- this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
- this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
- this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
- }
-
- @NonNull
- private static TimeZoneCapabilities createFromParcel(Parcel in) {
- return new TimeZoneCapabilities.Builder()
- .setConfiguration(in.readParcelable(null))
- .setConfigureAutoDetectionEnabled(in.readInt())
- .setConfigureGeoDetectionEnabled(in.readInt())
- .setSuggestManualTimeZone(in.readInt())
- .build();
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mConfiguration, flags);
- dest.writeInt(mConfigureAutoDetectionEnabled);
- dest.writeInt(mConfigureGeoDetectionEnabled);
- dest.writeInt(mSuggestManualTimeZone);
- }
-
- /**
- * Returns the user's time zone behavior configuration.
- */
- public @NonNull TimeZoneConfiguration getConfiguration() {
- return mConfiguration;
- }
-
- /**
- * Returns the capability state associated with the user's ability to modify the automatic time
- * zone detection setting. The setting can be updated via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
- * #getConfiguration()}.
- */
- @CapabilityState
- public int getConfigureAutoDetectionEnabled() {
- return mConfigureAutoDetectionEnabled;
- }
-
- /**
- * Returns the capability state associated with the user's ability to modify the geolocation
- * detection setting. The setting can be updated via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
- * #getConfiguration()}.
- */
- @CapabilityState
- public int getConfigureGeoDetectionEnabled() {
- return mConfigureGeoDetectionEnabled;
- }
-
- /**
- * Returns the capability state associated with the user's ability to manually set the time zone
- * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
- *
- * <p>The suggestion will be ignored in all cases unless the value is {@link
- * #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
- */
- @CapabilityState
- public int getSuggestManualTimeZone() {
- return mSuggestManualTimeZone;
- }
-
- /**
- * Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of
- * {@code requestedChanges}, if the current capabilities allow. The new configuration is
- * returned and the capabilities are left unchanged. If the capabilities do not permit one or
- * more of the changes then {@code null} is returned.
- */
- @Nullable
- public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) {
- if (requestedChanges.getUserId() != mConfiguration.getUserId()) {
- throw new IllegalArgumentException("User does not match:"
- + " this=" + mConfiguration + ", other=" + requestedChanges);
- }
-
- TimeZoneConfiguration.Builder newConfigBuilder =
- new TimeZoneConfiguration.Builder(mConfiguration);
- if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) {
- if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
- return null;
- }
- newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
- }
-
- if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) {
- if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
- return null;
- }
- newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
- }
-
- return newConfigBuilder.build();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TimeZoneCapabilities that = (TimeZoneCapabilities) o;
- return Objects.equals(mConfiguration, that.mConfiguration)
- && mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
- && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
- && mSuggestManualTimeZone == that.mSuggestManualTimeZone;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mConfiguration,
- mConfigureAutoDetectionEnabled,
- mConfigureGeoDetectionEnabled,
- mSuggestManualTimeZone);
- }
-
- @Override
- public String toString() {
- return "TimeZoneDetectorCapabilities{"
- + "mConfiguration=" + mConfiguration
- + ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
- + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
- + ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
- + '}';
- }
-
- /** @hide */
- public static class Builder {
-
- private TimeZoneConfiguration mConfiguration;
- private @CapabilityState int mConfigureAutoDetectionEnabled;
- private @CapabilityState int mConfigureGeoDetectionEnabled;
- private @CapabilityState int mSuggestManualTimeZone;
-
- /** Sets the user-visible configuration settings. */
- public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) {
- if (!configuration.isComplete()) {
- throw new IllegalArgumentException(configuration + " is not complete");
- }
- this.mConfiguration = configuration;
- return this;
- }
-
- /** Sets the state for the automatic time zone detection enabled config. */
- public Builder setConfigureAutoDetectionEnabled(@CapabilityState int value) {
- this.mConfigureAutoDetectionEnabled = value;
- return this;
- }
-
- /** Sets the state for the geolocation time zone detection enabled config. */
- public Builder setConfigureGeoDetectionEnabled(@CapabilityState int value) {
- this.mConfigureGeoDetectionEnabled = value;
- return this;
- }
-
- /** Sets the state for the suggestManualTimeZone action. */
- public Builder setSuggestManualTimeZone(@CapabilityState int value) {
- this.mSuggestManualTimeZone = value;
- return this;
- }
-
- /** Returns the {@link TimeZoneCapabilities}. */
- @NonNull
- public TimeZoneCapabilities build() {
- verifyCapabilitySet(mConfigureAutoDetectionEnabled, "configureAutoDetectionEnabled");
- verifyCapabilitySet(mConfigureGeoDetectionEnabled, "configureGeoDetectionEnabled");
- verifyCapabilitySet(mSuggestManualTimeZone, "suggestManualTimeZone");
- return new TimeZoneCapabilities(this);
- }
-
- private void verifyCapabilitySet(int value, String name) {
- if (value == 0) {
- throw new IllegalStateException(name + " not set");
- }
- }
- }
-}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 2b1cbf2..486232d 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -30,70 +30,6 @@
public interface TimeZoneDetector {
/**
- * Returns the current user's time zone capabilities. See {@link TimeZoneCapabilities}.
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @NonNull
- TimeZoneCapabilities getCapabilities();
-
- /**
- * Modifies the time zone detection configuration.
- *
- * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
- * specific to the current user.
- *
- * <p>The ability to modify configuration settings can be subject to restrictions. For
- * example, they may be determined by device hardware, general policy (i.e. only the primary
- * user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain
- * information at runtime about the user's capabilities.
- *
- * <p>Attempts to modify configuration settings with capabilities that are {@link
- * TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
- * TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
- * will be returned. Modifying configuration settings with capabilities that are {@link
- * TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
- * TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
- * TimeZoneCapabilities} for further details.
- *
- * <p>If the supplied configuration only has some values set, then only the specified settings
- * will be updated (where the user's capabilities allow) and other settings will be left
- * unchanged.
- *
- * @return {@code true} if all the configuration settings specified have been set to the
- * new values, {@code false} if none have
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
-
- /**
- * An interface that can be used to listen for changes to the time zone detector configuration.
- */
- @FunctionalInterface
- interface TimeZoneConfigurationListener {
- /**
- * Called when something about the time zone configuration on the device has changed.
- * This could be because the current user has changed, one of the device's relevant settings
- * has changed, or something that could affect a user's capabilities has changed.
- * There are no guarantees about the thread used.
- */
- void onChange();
- }
-
- /**
- * Registers a listener that will be informed when something about the time zone configuration
- * changes.
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
-
- /**
- * Removes a listener previously passed to
- * {@link #addConfigurationListener(ITimeZoneConfigurationListener)}
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
-
- /**
* A shared utility method to create a {@link ManualTimeZoneSuggestion}.
*
* @hide
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 4c69732..3bd6b4b 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -21,7 +21,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.ArraySet;
import android.util.Log;
/**
@@ -35,108 +34,12 @@
private final ITimeZoneDetectorService mITimeZoneDetectorService;
- private ITimeZoneConfigurationListener mConfigurationReceiver;
- private ArraySet<TimeZoneConfigurationListener> mConfigurationListeners;
-
public TimeZoneDetectorImpl() throws ServiceNotFoundException {
mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
}
@Override
- @NonNull
- public TimeZoneCapabilities getCapabilities() {
- if (DEBUG) {
- Log.d(TAG, "getCapabilities called");
- }
- try {
- return mITimeZoneDetectorService.getCapabilities();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
- public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
- if (DEBUG) {
- Log.d(TAG, "updateConfiguration called: " + configuration);
- }
- try {
- return mITimeZoneDetectorService.updateConfiguration(configuration);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
- public void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener) {
- if (DEBUG) {
- Log.d(TAG, "addConfigurationListener called: " + listener);
- }
- synchronized (this) {
- if (mConfigurationListeners.contains(listener)) {
- return;
- }
- if (mConfigurationReceiver == null) {
- ITimeZoneConfigurationListener iListener =
- new ITimeZoneConfigurationListener.Stub() {
- @Override
- public void onChange() {
- notifyConfigurationListeners();
- }
- };
- mConfigurationReceiver = iListener;
- }
- if (mConfigurationListeners == null) {
- mConfigurationListeners = new ArraySet<>();
- }
-
- boolean wasEmpty = mConfigurationListeners.isEmpty();
- mConfigurationListeners.add(listener);
- if (wasEmpty) {
- try {
- mITimeZoneDetectorService.addConfigurationListener(mConfigurationReceiver);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
- }
-
- private void notifyConfigurationListeners() {
- final ArraySet<TimeZoneConfigurationListener> configurationListeners;
- synchronized (this) {
- configurationListeners = new ArraySet<>(mConfigurationListeners);
- }
- int size = configurationListeners.size();
- for (int i = 0; i < size; i++) {
- configurationListeners.valueAt(i).onChange();
- }
- }
-
- @Override
- public void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener) {
- if (DEBUG) {
- Log.d(TAG, "removeConfigurationListener called: " + listener);
- }
-
- synchronized (this) {
- if (mConfigurationListeners == null) {
- return;
- }
- boolean wasEmpty = mConfigurationListeners.isEmpty();
- mConfigurationListeners.remove(listener);
- if (mConfigurationListeners.isEmpty() && !wasEmpty) {
- try {
- mITimeZoneDetectorService.removeConfigurationListener(mConfigurationReceiver);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
- }
-
- @Override
public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 005648f..666ba32 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -40,6 +40,7 @@
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.VrManager;
+import android.app.time.TimeManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -5090,6 +5091,14 @@
public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an {@link TimeManager}.
+ * @hide
+ *
+ * @see #getSystemService(String)
+ */
+ public static final String TIME_MANAGER = "time_manager";
+
+ /**
* Binder service name for {@link AppBindingService}.
* @hide
*/
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c2beab5..ea4b762 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1109,6 +1109,34 @@
}
/**
+ * Returns the reversed orientation.
+ * @hide
+ */
+ @ActivityInfo.ScreenOrientation
+ public static int reverseOrientation(@ActivityInfo.ScreenOrientation int orientation) {
+ switch (orientation) {
+ case SCREEN_ORIENTATION_LANDSCAPE:
+ return SCREEN_ORIENTATION_PORTRAIT;
+ case SCREEN_ORIENTATION_PORTRAIT:
+ return SCREEN_ORIENTATION_LANDSCAPE;
+ case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+ return SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+ case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+ return SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+ case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+ return SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+ case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+ return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ case SCREEN_ORIENTATION_USER_LANDSCAPE:
+ return SCREEN_ORIENTATION_USER_PORTRAIT;
+ case SCREEN_ORIENTATION_USER_PORTRAIT:
+ return SCREEN_ORIENTATION_USER_LANDSCAPE;
+ default:
+ return orientation;
+ }
+ }
+
+ /**
* Returns true if the activity supports picture-in-picture.
* @hide
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0e47b06..c293e4ad 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -866,6 +866,12 @@
* is set the restricted permissions will be whitelisted for all users, otherwise
* only to the owner.
*
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @hide
*/
public static final int INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS = 0x00400000;
@@ -3505,6 +3511,17 @@
public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
/**
+ * Permission flag: The permission is restricted but the app is exempt
+ * from the restriction and is allowed to hold this permission in its
+ * full form and the exemption is provided by the held roles.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 1 << 18;
+
+ /**
* Permission flags: Reserved for use by the permission controller. The platform and any
* packages besides the permission controller should not assume any definition about these
* flags.
@@ -3522,7 +3539,8 @@
public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
| FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
- | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
/**
* Mask for all permission flags.
@@ -3568,13 +3586,27 @@
/**
* Permission whitelist flag: permissions whitelisted by the system.
- * Permissions can also be whitelisted by the installer or on upgrade.
+ * Permissions can also be whitelisted by the installer, on upgrade, or on
+ * role grant.
+ *
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
*/
public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1 << 0;
/**
* Permission whitelist flag: permissions whitelisted by the installer.
- * Permissions can also be whitelisted by the system or on upgrade.
+ * Permissions can also be whitelisted by the system, on upgrade, or on role
+ * grant.
+ *
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
*/
public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 1 << 1;
@@ -3582,15 +3614,31 @@
* Permission whitelist flag: permissions whitelisted by the system
* when upgrading from an OS version where the permission was not
* restricted to an OS version where the permission is restricted.
- * Permissions can also be whitelisted by the installer or the system.
+ * Permissions can also be whitelisted by the installer, the system, or on
+ * role grant.
+ *
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
*/
public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 1 << 2;
+ /**
+ * Permission allowlist flag: permissions exempted by the system
+ * when being granted a role.
+ * Permissions can also be exempted by the installer, the system, or on
+ * upgrade.
+ */
+ public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 1 << 3;
+
/** @hide */
@IntDef(flag = true, prefix = {"FLAG_PERMISSION_WHITELIST_"}, value = {
FLAG_PERMISSION_WHITELIST_SYSTEM,
FLAG_PERMISSION_WHITELIST_INSTALLER,
- FLAG_PERMISSION_WHITELIST_UPGRADE
+ FLAG_PERMISSION_WHITELIST_UPGRADE,
+ FLAG_PERMISSION_ALLOWLIST_ROLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface PermissionWhitelistFlags {}
@@ -4569,7 +4617,7 @@
* allows for the to hold that permission and whitelisting a soft restricted
* permission allows the app to hold the permission in its full, unrestricted form.
*
- * <p><ol>There are three whitelists:
+ * <p><ol>There are four allowlists:
*
* <li>one for cases where the system permission policy whitelists a permission
* This list corresponds to the{@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag.
@@ -4586,6 +4634,17 @@
* Can be accessed by pre-installed holders of a dedicated permission or the
* installer on record.
*
+ * <li>one for cases where the system exempts the permission when granting a role.
+ * This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can
+ * be accessed by pre-installed holders of a dedicated permission.
+ * </ol>
+ *
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @param packageName The app for which to get whitelisted permissions.
* @param whitelistFlag The flag to determine which whitelist to query. Only one flag
* can be passed.s
@@ -4596,6 +4655,7 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
+ * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to access a whitelist that you have no access to.
*/
@@ -4617,7 +4677,7 @@
* allows for the to hold that permission and whitelisting a soft restricted
* permission allows the app to hold the permission in its full, unrestricted form.
*
- * <p><ol>There are three whitelists:
+ * <p><ol>There are four whitelists:
*
* <li>one for cases where the system permission policy whitelists a permission
* This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag.
@@ -4635,10 +4695,21 @@
* Can be modified by pre-installed holders of a dedicated permission or the installer
* on record.
*
+ * <li>one for cases where the system exempts the permission when permission when
+ * granting a role. This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE}
+ * flag. Can be modified by pre-installed holders of a dedicated permission.
+ * </ol>
+ *
* <p>You need to specify the whitelists for which to set the whitelisted permissions
* which will clear the previous whitelisted permissions and replace them with the
* provided ones.
*
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @param packageName The app for which to get whitelisted permissions.
* @param permName The whitelisted permission to add.
* @param whitelistFlags The whitelists to which to add. Passing multiple flags
@@ -4650,6 +4721,7 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
+ * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to modify a whitelist that you have no access to.
*/
@@ -4671,7 +4743,7 @@
* allows for the to hold that permission and whitelisting a soft restricted
* permission allows the app to hold the permission in its full, unrestricted form.
*
- * <p><ol>There are three whitelists:
+ * <p><ol>There are four whitelists:
*
* <li>one for cases where the system permission policy whitelists a permission
* This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag.
@@ -4689,10 +4761,24 @@
* Can be modified by pre-installed holders of a dedicated permission or the installer
* on record.
*
+ * <li>one for cases where the system exempts the permission when upgrading
+ * from an OS version in which the permission was not restricted to an OS version
+ * in which the permission is restricted. This list corresponds to the {@link
+ * #FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be modified by pre-installed
+ * holders of a dedicated permission. The installer on record can only remove
+ * permissions from this allowlist.
+ * </ol>
+ *
* <p>You need to specify the whitelists for which to set the whitelisted permissions
* which will clear the previous whitelisted permissions and replace them with the
* provided ones.
*
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @param packageName The app for which to get whitelisted permissions.
* @param permName The whitelisted permission to remove.
* @param whitelistFlags The whitelists from which to remove. Passing multiple flags
@@ -4704,6 +4790,7 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
+ * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to modify a whitelist that you have no access to.
*/
@@ -4724,6 +4811,12 @@
* un-whitelist the packages it installs, unless auto-revoking permissions from that package
* would cause breakages beyond having to re-request the permission(s).
*
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @param packageName The app for which to set exemption.
* @param whitelisted Whether the app should be whitelisted.
*
@@ -4745,6 +4838,13 @@
*
* Only the installer on record that installed the given package, or a holder of
* {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+ *
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @param packageName The app for which to set exemption.
*
* @return Whether the app is whitelisted.
@@ -8059,6 +8159,12 @@
}
/**
+ * <p>
+ * <strong>Note: </strong>In retrospect it would have been preferred to use
+ * more inclusive terminology when naming this API. Similar APIs added will
+ * refrain from using the term "whitelist".
+ * </p>
+ *
* @return whether this package is whitelisted from having its runtime permission be
* auto-revoked if unused for an extended period of time.
*/
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 04e15c2..5d4c843 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -377,6 +377,14 @@
public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4;
/**
+ * Flag for {@link #flags}, corresponding to <code>installerExemptIgnored</code>
+ * value of {@link android.R.attr#permissionFlags}.
+ *
+ * <p> Modifier for permission restriction. This permission cannot be exempted by the installer.
+ */
+ public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 1 << 5;
+
+ /**
* Flag for {@link #flags}, indicating that this permission has been
* installed into the system's globally defined permissions.
*/
@@ -656,6 +664,11 @@
}
/** @hide */
+ public boolean isInstallerExemptIgnored() {
+ return (flags & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
+ }
+
+ /** @hide */
public boolean isAppOp() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
}
diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java
index 0f33ac4..b3dcb8f 100644
--- a/core/java/android/hardware/biometrics/SensorProperties.java
+++ b/core/java/android/hardware/biometrics/SensorProperties.java
@@ -17,66 +17,71 @@
package android.hardware.biometrics;
import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * The base class containing all sensor-agnostic information. This is a superset of the
- * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
- * behavior with the older generation of HIDL (non-AIDL) interfaces.
+ * The base class containing all modality-agnostic information.
* @hide
*/
-public class SensorProperties implements Parcelable {
-
+public class SensorProperties {
+ /**
+ * A sensor that meets the requirements for Class 1 biometrics as defined in the CDD. This does
+ * not correspond to a public BiometricManager.Authenticators constant. Sensors of this strength
+ * are not available to applications via the public API surface.
+ * @hide
+ */
public static final int STRENGTH_CONVENIENCE = 0;
+
+ /**
+ * A sensor that meets the requirements for Class 2 biometrics as defined in the CDD.
+ * Corresponds to BiometricManager.Authenticators.BIOMETRIC_WEAK.
+ * @hide
+ */
public static final int STRENGTH_WEAK = 1;
+
+ /**
+ * A sensor that meets the requirements for Class 3 biometrics as defined in the CDD.
+ * Corresponds to BiometricManager.Authenticators.BIOMETRIC_STRONG.
+ *
+ * Notably, this is the only strength that allows generation of HardwareAuthToken(s).
+ * @hide
+ */
public static final int STRENGTH_STRONG = 2;
+ /**
+ * @hide
+ */
@IntDef({STRENGTH_CONVENIENCE, STRENGTH_WEAK, STRENGTH_STRONG})
@Retention(RetentionPolicy.SOURCE)
public @interface Strength {}
- public final int sensorId;
- @Strength public final int sensorStrength;
- public final int maxEnrollmentsPerUser;
+ private final int mSensorId;
+ @Strength private final int mSensorStrength;
- protected SensorProperties(int sensorId, @Strength int sensorStrength,
- int maxEnrollmentsPerUser) {
- this.sensorId = sensorId;
- this.sensorStrength = sensorStrength;
- this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+ /**
+ * @hide
+ */
+ public SensorProperties(int sensorId, @Strength int sensorStrength) {
+ mSensorId = sensorId;
+ mSensorStrength = sensorStrength;
}
- protected SensorProperties(Parcel in) {
- sensorId = in.readInt();
- sensorStrength = in.readInt();
- maxEnrollmentsPerUser = in.readInt();
+ /**
+ * @return The sensor's unique identifier.
+ * @hide
+ */
+ public int getSensorId() {
+ return mSensorId;
}
- public static final Creator<SensorProperties> CREATOR = new Creator<SensorProperties>() {
- @Override
- public SensorProperties createFromParcel(Parcel in) {
- return new SensorProperties(in);
- }
-
- @Override
- public SensorProperties[] newArray(int size) {
- return new SensorProperties[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(sensorId);
- dest.writeInt(sensorStrength);
- dest.writeInt(maxEnrollmentsPerUser);
+ /**
+ * @return The sensor's strength.
+ * @hide
+ */
+ @Strength
+ public int getSensorStrength() {
+ return mSensorStrength;
}
}
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
new file mode 100644
index 0000000..2189de08
--- /dev/null
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The base class containing all modality-agnostic information. This is a superset of the
+ * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
+ * behavior with the older generation of HIDL (non-AIDL) interfaces.
+ * @hide
+ */
+public class SensorPropertiesInternal implements Parcelable {
+
+ public final int sensorId;
+ @SensorProperties.Strength public final int sensorStrength;
+ public final int maxEnrollmentsPerUser;
+
+ protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
+ int maxEnrollmentsPerUser) {
+ this.sensorId = sensorId;
+ this.sensorStrength = sensorStrength;
+ this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+ }
+
+ protected SensorPropertiesInternal(Parcel in) {
+ sensorId = in.readInt();
+ sensorStrength = in.readInt();
+ maxEnrollmentsPerUser = in.readInt();
+ }
+
+ public static final Creator<SensorPropertiesInternal> CREATOR =
+ new Creator<SensorPropertiesInternal>() {
+ @Override
+ public SensorPropertiesInternal createFromParcel(Parcel in) {
+ return new SensorPropertiesInternal(in);
+ }
+
+ @Override
+ public SensorPropertiesInternal[] newArray(int size) {
+ return new SensorPropertiesInternal[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(sensorId);
+ dest.writeInt(sensorStrength);
+ dest.writeInt(maxEnrollmentsPerUser);
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 986e6ea..9d4ab0b 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -72,6 +72,7 @@
import android.util.Size;
import dalvik.annotation.optimization.FastNative;
+import dalvik.system.VMRuntime;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -351,6 +352,7 @@
if (mMetadataPtr == 0) {
throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
}
+ updateNativeAllocation();
}
/**
@@ -362,6 +364,7 @@
if (mMetadataPtr == 0) {
throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
}
+ updateNativeAllocation();
}
/**
@@ -443,6 +446,7 @@
public void readFromParcel(Parcel in) {
nativeReadFromParcel(in, mMetadataPtr);
+ updateNativeAllocation();
}
/**
@@ -533,6 +537,11 @@
// Delete native pointer, but does not clear it
nativeClose(mMetadataPtr);
mMetadataPtr = 0;
+
+ if (mBufferSize > 0) {
+ VMRuntime.getRuntime().registerNativeFree(mBufferSize);
+ }
+ mBufferSize = 0;
}
private <T> T getBase(CameraCharacteristics.Key<T> key) {
@@ -1645,9 +1654,26 @@
return true;
}
+ private void updateNativeAllocation() {
+ long currentBufferSize = nativeGetBufferSize(mMetadataPtr);
+
+ if (currentBufferSize != mBufferSize) {
+ if (mBufferSize > 0) {
+ VMRuntime.getRuntime().registerNativeFree(mBufferSize);
+ }
+
+ mBufferSize = currentBufferSize;
+
+ if (mBufferSize > 0) {
+ VMRuntime.getRuntime().registerNativeAllocation(mBufferSize);
+ }
+ }
+ }
+
private int mCameraId = -1;
private boolean mHasMandatoryConcurrentStreams = false;
private Size mDisplaySize = new Size(0, 0);
+ private long mBufferSize = 0;
/**
* Set the current camera Id.
@@ -1705,6 +1731,8 @@
private static synchronized native boolean nativeIsEmpty(long ptr);
@FastNative
private static synchronized native int nativeGetEntryCount(long ptr);
+ @FastNative
+ private static synchronized native long nativeGetBufferSize(long ptr);
@UnsupportedAppUsage
@FastNative
@@ -1744,6 +1772,8 @@
mCameraId = other.mCameraId;
mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams;
mDisplaySize = other.mDisplaySize;
+ updateNativeAllocation();
+ other.updateNativeAllocation();
}
/**
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 1b114d3..e65d7b5 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -49,9 +49,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
/**
* A class that coordinates access to the face authentication hardware.
@@ -299,6 +296,7 @@
* int[], Surface)} with {@code surface} set to null.
*
* @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface)
+ * @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
@@ -443,7 +441,8 @@
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void generateChallenge(GenerateChallengeCallback callback) {
- final List<FaceSensorProperties> faceSensorProperties = getSensorProperties();
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
if (faceSensorProperties.isEmpty()) {
Slog.e(TAG, "No sensors");
return;
@@ -460,7 +459,8 @@
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void revokeChallenge() {
- final List<FaceSensorProperties> faceSensorProperties = getSensorProperties();
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
if (faceSensorProperties.isEmpty()) {
Slog.e(TAG, "No sensors during revokeChallenge");
}
@@ -597,6 +597,7 @@
* Determine if there is a face enrolled.
*
* @return true if a face is enrolled, false otherwise
+ * @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledTemplates() {
@@ -632,6 +633,7 @@
* Determine if face authentication sensor hardware is present and functional.
*
* @return true if hardware is present and functional, false otherwise.
+ * @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean isHardwareDetected() {
@@ -648,17 +650,32 @@
}
/**
+ * Retrieves a list of properties for all face authentication sensors on the device.
+ * @hide
+ */
+ @NonNull
+ public List<FaceSensorProperties> getSensorProperties() {
+ final List<FaceSensorProperties> properties = new ArrayList<>();
+ final List<FaceSensorPropertiesInternal> internalProperties
+ = getSensorPropertiesInternal();
+ for (FaceSensorPropertiesInternal internalProp : internalProperties) {
+ properties.add(FaceSensorProperties.from(internalProp));
+ }
+ return properties;
+ }
+
+ /**
* Get statically configured sensor properties.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@NonNull
- public List<FaceSensorProperties> getSensorProperties() {
+ public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
return new ArrayList<>();
}
- return mService.getSensorProperties(mContext.getOpPackageName());
+ return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -874,6 +891,7 @@
/**
* Container for callback data from {@link FaceManager#authenticate(CryptoObject,
* CancellationSignal, int, AuthenticationCallback, Handler)}.
+ * @hide
*/
public static class AuthenticationResult {
private Face mFace;
@@ -943,6 +961,7 @@
* FaceManager#authenticate(CryptoObject, CancellationSignal,
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening
* to face events.
+ * @hide
*/
public abstract static class AuthenticationCallback
extends BiometricAuthenticator.AuthenticationCallback {
diff --git a/core/java/android/hardware/face/FaceSensorProperties.java b/core/java/android/hardware/face/FaceSensorProperties.java
index 23ad935..e61d931 100644
--- a/core/java/android/hardware/face/FaceSensorProperties.java
+++ b/core/java/android/hardware/face/FaceSensorProperties.java
@@ -16,76 +16,25 @@
package android.hardware.face;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.hardware.biometrics.SensorProperties;
/**
* Container for face sensor properties.
* @hide
*/
-public class FaceSensorProperties implements Parcelable {
+public class FaceSensorProperties extends SensorProperties {
/**
- * A statically configured ID representing this sensor. Sensor IDs must be unique across all
- * biometrics across the device, starting at 0, and in increments of 1.
+ * @hide
*/
- public final int sensorId;
+ public static FaceSensorProperties from(FaceSensorPropertiesInternal internalProp) {
+ return new FaceSensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+ }
/**
- * True if the sensor is able to perform generic face detection, without running the
- * matching algorithm, and without affecting the lockout counter.
+ * @hide
*/
- public final boolean supportsFaceDetection;
- /**
- * True if the sensor is able to provide self illumination in dark scenarios, without support
- * from above the HAL.
- */
- public final boolean supportsSelfIllumination;
- /**
- * Maximum number of enrollments a user/profile can have.
- */
- public final int maxTemplatesAllowed;
-
- /**
- * Initializes SensorProperties with specified values
- */
- public FaceSensorProperties(int sensorId, boolean supportsFaceDetection,
- boolean supportsSelfIllumination, int maxTemplatesAllowed) {
- this.sensorId = sensorId;
- this.supportsFaceDetection = supportsFaceDetection;
- this.supportsSelfIllumination = supportsSelfIllumination;
- this.maxTemplatesAllowed = maxTemplatesAllowed;
+ public FaceSensorProperties(int sensorId, int sensorStrength) {
+ super(sensorId, sensorStrength);
}
- protected FaceSensorProperties(Parcel in) {
- sensorId = in.readInt();
- supportsFaceDetection = in.readBoolean();
- supportsSelfIllumination = in.readBoolean();
- maxTemplatesAllowed = in.readInt();
- }
-
- public static final Creator<FaceSensorProperties> CREATOR =
- new Creator<FaceSensorProperties>() {
- @Override
- public FaceSensorProperties createFromParcel(Parcel in) {
- return new FaceSensorProperties(in);
- }
-
- @Override
- public FaceSensorProperties[] newArray(int size) {
- return new FaceSensorProperties[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(sensorId);
- dest.writeBoolean(supportsFaceDetection);
- dest.writeBoolean(supportsSelfIllumination);
- dest.writeInt(maxTemplatesAllowed);
- }
}
diff --git a/core/java/android/hardware/face/FaceSensorProperties.aidl b/core/java/android/hardware/face/FaceSensorPropertiesInternal.aidl
similarity index 93%
rename from core/java/android/hardware/face/FaceSensorProperties.aidl
rename to core/java/android/hardware/face/FaceSensorPropertiesInternal.aidl
index d83ee4b..75bc250 100644
--- a/core/java/android/hardware/face/FaceSensorProperties.aidl
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.aidl
@@ -15,4 +15,4 @@
*/
package android.hardware.face;
-parcelable FaceSensorProperties;
\ No newline at end of file
+parcelable FaceSensorPropertiesInternal;
\ No newline at end of file
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
new file mode 100644
index 0000000..e91554b
--- /dev/null
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.face;
+
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.biometrics.SensorPropertiesInternal;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for face sensor properties.
+ * @hide
+ */
+public class FaceSensorPropertiesInternal extends SensorPropertiesInternal {
+ /**
+ * True if the sensor is able to perform generic face detection, without running the
+ * matching algorithm, and without affecting the lockout counter.
+ */
+ public final boolean supportsFaceDetection;
+ /**
+ * True if the sensor is able to provide self illumination in dark scenarios, without support
+ * from above the HAL.
+ */
+ public final boolean supportsSelfIllumination;
+
+ /**
+ * Initializes SensorProperties with specified values
+ */
+ public FaceSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength,
+ int maxEnrollmentsPerUser, boolean supportsFaceDetection,
+ boolean supportsSelfIllumination) {
+ super(sensorId, strength, maxEnrollmentsPerUser);
+ this.supportsFaceDetection = supportsFaceDetection;
+ this.supportsSelfIllumination = supportsSelfIllumination;
+ }
+
+ protected FaceSensorPropertiesInternal(Parcel in) {
+ super(in);
+ supportsFaceDetection = in.readBoolean();
+ supportsSelfIllumination = in.readBoolean();
+ }
+
+ public static final Creator<FaceSensorPropertiesInternal> CREATOR =
+ new Creator<FaceSensorPropertiesInternal>() {
+ @Override
+ public FaceSensorPropertiesInternal createFromParcel(Parcel in) {
+ return new FaceSensorPropertiesInternal(in);
+ }
+
+ @Override
+ public FaceSensorPropertiesInternal[] newArray(int size) {
+ return new FaceSensorPropertiesInternal[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeBoolean(supportsFaceDetection);
+ dest.writeBoolean(supportsSelfIllumination);
+ }
+}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index e744c84..b85b6f7 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -19,7 +19,7 @@
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
-import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.view.Surface;
/**
@@ -29,7 +29,7 @@
*/
interface IFaceService {
// Retrieve static sensor properties for all face sensors
- List<FaceSensorProperties> getSensorProperties(String opPackageName);
+ List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
// Authenticate the given sessionId with a face
void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver,
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 997efbe..23de303 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -53,10 +53,7 @@
import java.security.Signature;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -608,7 +605,8 @@
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void generateChallenge(GenerateChallengeCallback callback) {
- final List<FingerprintSensorProperties> fingerprintSensorProperties = getSensorProperties();
+ final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
+ getSensorPropertiesInternal();
if (fingerprintSensorProperties.isEmpty()) {
Slog.e(TAG, "No sensors");
return;
@@ -850,17 +848,32 @@
}
/**
+ * Retrieves a list of properties for all fingerprint sensors on the device.
+ * @hide
+ */
+ @NonNull
+ public List<FingerprintSensorProperties> getSensorProperties() {
+ final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> internalProperties
+ = getSensorPropertiesInternal();
+ for (FingerprintSensorPropertiesInternal internalProp : internalProperties) {
+ properties.add(FingerprintSensorProperties.from(internalProp));
+ }
+ return properties;
+ }
+
+ /**
* Get statically configured sensor properties.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@NonNull
- public List<FingerprintSensorProperties> getSensorProperties() {
+ public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
return new ArrayList<>();
}
- return mService.getSensorProperties(mContext.getOpPackageName());
+ return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index d26346c..684d7d9 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.hardware.biometrics.SensorProperties;
-import android.os.Parcel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -28,14 +27,39 @@
* @hide
*/
public class FingerprintSensorProperties extends SensorProperties {
-
+ /**
+ * @hide
+ */
public static final int TYPE_UNKNOWN = 0;
+
+ /**
+ * @hide
+ */
public static final int TYPE_REAR = 1;
+
+ /**
+ * @hide
+ */
public static final int TYPE_UDFPS_ULTRASONIC = 2;
+
+ /**
+ * @hide
+ */
public static final int TYPE_UDFPS_OPTICAL = 3;
+
+ /**
+ * @hide
+ */
public static final int TYPE_POWER_BUTTON = 4;
+
+ /**
+ * @hide
+ */
public static final int TYPE_HOME_BUTTON = 5;
+ /**
+ * @hide
+ */
@IntDef({TYPE_UNKNOWN,
TYPE_REAR,
TYPE_UDFPS_ULTRASONIC,
@@ -45,60 +69,34 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SensorType {}
- public final @SensorType int sensorType;
- // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
- // cannot be checked
- public final boolean resetLockoutRequiresHardwareAuthToken;
+ @SensorType final int mSensorType;
/**
- * Initializes SensorProperties with specified values
+ * Constructs a {@link FingerprintSensorProperties} from the internal parcelable representation.
+ * @hide
*/
- public FingerprintSensorProperties(int sensorId, @Strength int strength,
- int maxEnrollmentsPerUser, @SensorType int sensorType,
- boolean resetLockoutRequiresHardwareAuthToken) {
- super(sensorId, strength, maxEnrollmentsPerUser);
- this.sensorType = sensorType;
- this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
+ public static FingerprintSensorProperties from(
+ FingerprintSensorPropertiesInternal internalProp) {
+ return new FingerprintSensorProperties(internalProp.sensorId,
+ internalProp.sensorStrength,
+ internalProp.sensorType);
}
- protected FingerprintSensorProperties(Parcel in) {
- super(in);
- sensorType = in.readInt();
- resetLockoutRequiresHardwareAuthToken = in.readBoolean();
+ /**
+ * @hide
+ */
+ public FingerprintSensorProperties(int sensorId, int sensorStrength,
+ @SensorType int sensorType) {
+ super(sensorId, sensorStrength);
+ mSensorType = sensorType;
}
- public static final Creator<FingerprintSensorProperties> CREATOR =
- new Creator<FingerprintSensorProperties>() {
- @Override
- public FingerprintSensorProperties createFromParcel(Parcel in) {
- return new FingerprintSensorProperties(in);
- }
-
- @Override
- public FingerprintSensorProperties[] newArray(int size) {
- return new FingerprintSensorProperties[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(sensorType);
- dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
- }
-
- public boolean isAnyUdfpsType() {
- switch (sensorType) {
- case TYPE_UDFPS_OPTICAL:
- case TYPE_UDFPS_ULTRASONIC:
- return true;
- default:
- return false;
- }
+ /**
+ * @hide
+ * @return The sensor's type.
+ */
+ @SensorType
+ public int getSensorType() {
+ return mSensorType;
}
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.aidl b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.aidl
similarity index 92%
rename from core/java/android/hardware/fingerprint/FingerprintSensorProperties.aidl
rename to core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.aidl
index 83d853d..51705ef 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.aidl
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.aidl
@@ -15,4 +15,4 @@
*/
package android.hardware.fingerprint;
-parcelable FingerprintSensorProperties;
\ No newline at end of file
+parcelable FingerprintSensorPropertiesInternal;
\ No newline at end of file
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
new file mode 100644
index 0000000..d5ce9e3
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.fingerprint;
+
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
+
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.biometrics.SensorPropertiesInternal;
+import android.os.Parcel;
+
+/**
+ * Container for fingerprint sensor properties.
+ * @hide
+ */
+public class FingerprintSensorPropertiesInternal extends SensorPropertiesInternal {
+ public final @FingerprintSensorProperties.SensorType int sensorType;
+ // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
+ // cannot be checked
+ public final boolean resetLockoutRequiresHardwareAuthToken;
+
+ /**
+ * Initializes SensorProperties with specified values
+ */
+ public FingerprintSensorPropertiesInternal(int sensorId,
+ @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+ @FingerprintSensorProperties.SensorType int sensorType,
+ boolean resetLockoutRequiresHardwareAuthToken) {
+ super(sensorId, strength, maxEnrollmentsPerUser);
+ this.sensorType = sensorType;
+ this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
+ }
+
+ protected FingerprintSensorPropertiesInternal(Parcel in) {
+ super(in);
+ sensorType = in.readInt();
+ resetLockoutRequiresHardwareAuthToken = in.readBoolean();
+ }
+
+ public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
+ new Creator<FingerprintSensorPropertiesInternal>() {
+ @Override
+ public FingerprintSensorPropertiesInternal createFromParcel(Parcel in) {
+ return new FingerprintSensorPropertiesInternal(in);
+ }
+
+ @Override
+ public FingerprintSensorPropertiesInternal[] newArray(int size) {
+ return new FingerprintSensorPropertiesInternal[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(sensorType);
+ dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
+ }
+
+ public boolean isAnyUdfpsType() {
+ switch (sensorType) {
+ case TYPE_UDFPS_OPTICAL:
+ case TYPE_UDFPS_ULTRASONIC:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 68013ea..7af7380 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -21,7 +21,7 @@
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.view.Surface;
import java.util.List;
@@ -31,7 +31,7 @@
*/
interface IFingerprintService {
// Retrieve static sensor properties for all fingerprint sensors
- List<FingerprintSensorProperties> getSensorProperties(String opPackageName);
+ List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
// Authenticate the given sessionId with a fingerprint. This is protected by
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index cad103e9..651494d 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -21,14 +21,13 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.util.LinkPropertiesUtils;
+import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import com.android.net.module.util.LinkPropertiesUtils;
-import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
-
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 51c5a50..0eb3c1e 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,12 +20,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
-import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index a8b45e9..9876076 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -22,12 +22,11 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.util.NetUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.net.module.util.NetUtils;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 21fd819..ab5637c 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -16,7 +16,6 @@
package android.os;
-import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.SOCK_STREAM;
import android.system.ErrnoException;
@@ -58,17 +57,19 @@
/** CMD_CLOSE */
private static final int CMD_CLOSE = 3;
- private FileDescriptor mTarget;
+ private ParcelFileDescriptor mTarget;
- private final FileDescriptor mServer = new FileDescriptor();
- private final FileDescriptor mClient = new FileDescriptor();
+ private ParcelFileDescriptor mServer;
+ private ParcelFileDescriptor mClient;
private volatile boolean mClosed;
public FileBridge() {
try {
- Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient);
- } catch (ErrnoException e) {
+ ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(SOCK_STREAM);
+ mServer = fds[0];
+ mClient = fds[1];
+ } catch (IOException e) {
throw new RuntimeException("Failed to create bridge");
}
}
@@ -80,15 +81,14 @@
public void forceClose() {
IoUtils.closeQuietly(mTarget);
IoUtils.closeQuietly(mServer);
- IoUtils.closeQuietly(mClient);
mClosed = true;
}
- public void setTargetFile(FileDescriptor target) {
+ public void setTargetFile(ParcelFileDescriptor target) {
mTarget = target;
}
- public FileDescriptor getClientSocket() {
+ public ParcelFileDescriptor getClientSocket() {
return mClient;
}
@@ -96,32 +96,33 @@
public void run() {
final byte[] temp = new byte[8192];
try {
- while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
+ while (IoBridge.read(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH) == MSG_LENGTH) {
final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
if (cmd == CMD_WRITE) {
// Shuttle data into local file
int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
while (len > 0) {
- int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
+ int n = IoBridge.read(mServer.getFileDescriptor(), temp, 0,
+ Math.min(temp.length, len));
if (n == -1) {
throw new IOException(
"Unexpected EOF; still expected " + len + " bytes");
}
- IoBridge.write(mTarget, temp, 0, n);
+ IoBridge.write(mTarget.getFileDescriptor(), temp, 0, n);
len -= n;
}
} else if (cmd == CMD_FSYNC) {
// Sync and echo back to confirm
- Os.fsync(mTarget);
- IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+ Os.fsync(mTarget.getFileDescriptor());
+ IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH);
} else if (cmd == CMD_CLOSE) {
// Close and echo back to confirm
- Os.fsync(mTarget);
- Os.close(mTarget);
+ Os.fsync(mTarget.getFileDescriptor());
+ mTarget.close();
mClosed = true;
- IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+ IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH);
break;
}
}
@@ -143,17 +144,11 @@
mClient = clientPfd.getFileDescriptor();
}
- public FileBridgeOutputStream(FileDescriptor client) {
- mClientPfd = null;
- mClient = client;
- }
-
@Override
public void close() throws IOException {
try {
writeCommandAndBlock(CMD_CLOSE, "close()");
} finally {
- IoBridge.closeAndSignalBlockedThreads(mClient);
IoUtils.closeQuietly(mClientPfd);
}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 54f80c6..6ba1627 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -49,6 +49,9 @@
/**
* GraphicsEnvironment sets up necessary properties for the graphics environment of the
* application process.
+ * GraphicsEnvironment uses a bunch of settings global variables to determine the setup,
+ * the change of settings global variables will only take effect before setup() is called,
+ * and any subsequent change will not impact the current running processes.
*
* @hide
*/
@@ -119,6 +122,8 @@
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
+ private int mAngleOptInIndex = -1;
+
/**
* Set up GraphicsEnvironment
*/
@@ -146,15 +151,9 @@
}
/**
- * Hint for GraphicsEnvironment that an activity is launching on the process.
- * Then the app process is allowed to send stats to GpuStats module.
- */
- public static native void hintActivityLaunch();
-
- /**
* Query to determine if ANGLE should be used
*/
- public static boolean shouldUseAngle(Context context, Bundle coreSettings,
+ private boolean shouldUseAngle(Context context, Bundle coreSettings,
String packageName) {
if (TextUtils.isEmpty(packageName)) {
Log.v(TAG, "No package name specified, ANGLE should not be used");
@@ -182,7 +181,7 @@
return allowed || requested;
}
- private static int getVulkanVersion(PackageManager pm) {
+ private int getVulkanVersion(PackageManager pm) {
// PackageManager doesn't have an API to retrieve the version of a specific feature, and we
// need to avoid retrieving all system features here and looping through them.
if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_1)) {
@@ -199,7 +198,7 @@
/**
* Check whether application is has set the manifest metadata for layer injection.
*/
- private static boolean canInjectLayers(ApplicationInfo ai) {
+ private boolean canInjectLayers(ApplicationInfo ai) {
return (ai.metaData != null && ai.metaData.getBoolean(METADATA_INJECT_LAYERS_ENABLE)
&& setInjectLayersPrSetDumpable());
}
@@ -257,7 +256,7 @@
/**
* Return the debug layer app's on-disk and in-APK lib directories
*/
- private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
+ private String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
final ApplicationInfo appInfo;
try {
appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
@@ -355,11 +354,10 @@
return valueList;
}
- private static int getGlobalSettingsPkgIndex(String pkgName,
- List<String> globalSettingsDriverPkgs) {
- for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
- if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
- return pkgIndex;
+ private static int getPackageIndex(String packageName, List<String> packages) {
+ for (int idx = 0; idx < packages.size(); idx++) {
+ if (packages.get(idx).equals(packageName)) {
+ return idx;
}
}
@@ -380,7 +378,7 @@
return ai;
}
- private static String getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ private String getDriverForPackage(Context context, Bundle bundle, String packageName) {
final int allUseAngle;
if (bundle != null) {
allUseAngle =
@@ -402,31 +400,32 @@
}
final ContentResolver contentResolver = context.getContentResolver();
- final List<String> globalSettingsDriverPkgs =
+ final List<String> optInPackages =
getGlobalSettingsString(contentResolver, bundle,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
- final List<String> globalSettingsDriverValues =
+ final List<String> optInValues =
getGlobalSettingsString(contentResolver, bundle,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
// Make sure we have good settings to use
- if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) {
+ if (optInPackages.size() != optInValues.size()) {
Log.w(TAG,
"Global.Settings values are invalid: "
+ "number of packages: "
- + globalSettingsDriverPkgs.size() + ", "
+ + optInPackages.size() + ", "
+ "number of values: "
- + globalSettingsDriverValues.size());
+ + optInValues.size());
return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
}
- final int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
+ final int pkgIndex = getPackageIndex(packageName, optInPackages);
if (pkgIndex < 0) {
return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
}
+ mAngleOptInIndex = pkgIndex;
- return globalSettingsDriverValues.get(pkgIndex);
+ return optInValues.get(pkgIndex);
}
/**
@@ -480,7 +479,7 @@
* True: Temporary rules file was loaded.
* False: Temporary rules file was *not* loaded.
*/
- private static boolean setupAngleWithTempRulesFile(Context context,
+ private boolean setupAngleWithTempRulesFile(Context context,
String packageName,
String paths,
String devOptIn) {
@@ -516,7 +515,8 @@
final long rulesLength = stream.getChannel().size();
Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
- setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
+ setAngleInfo(paths, packageName, devOptIn, null,
+ rulesFd, rulesOffset, rulesLength);
stream.close();
@@ -540,12 +540,13 @@
* True: APK rules file was loaded.
* False: APK rules file was *not* loaded.
*/
- private static boolean setupAngleRulesApk(String anglePkgName,
+ private boolean setupAngleRulesApk(String anglePkgName,
ApplicationInfo angleInfo,
PackageManager pm,
String packageName,
String paths,
- String devOptIn) {
+ String devOptIn,
+ String[] features) {
// Pass the rules file to loader for ANGLE decisions
try {
final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
@@ -553,7 +554,7 @@
try {
final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
- setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
+ setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(),
assetsFd.getStartOffset(), assetsFd.getLength());
assetsFd.close();
@@ -573,7 +574,7 @@
/**
* Pull ANGLE allowlist from GlobalSettings and compare against current package
*/
- private static boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
+ private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
final ContentResolver contentResolver = context.getContentResolver();
final List<String> angleAllowlist =
getGlobalSettingsString(contentResolver, bundle,
@@ -659,8 +660,11 @@
return true;
}
- if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
- // We setup ANGLE with rules from the APK, so we're done here.
+ String[] features = getAngleEglFeatures(context, bundle);
+
+ if (setupAngleRulesApk(
+ anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
+ // ANGLE with rules is set up from the APK, hence return.
return true;
}
@@ -726,10 +730,23 @@
}
}
+ private String[] getAngleEglFeatures(Context context, Bundle coreSettings) {
+ if (mAngleOptInIndex < 0) {
+ return null;
+ }
+
+ final List<String> featuresLists = getGlobalSettingsString(
+ context.getContentResolver(), coreSettings, Settings.Global.ANGLE_EGL_FEATURES);
+ if (featuresLists.size() <= mAngleOptInIndex) {
+ return null;
+ }
+ return featuresLists.get(mAngleOptInIndex).split(":");
+ }
+
/**
* Return the driver package name to use. Return null for system driver.
*/
- private static String chooseDriverInternal(Bundle coreSettings, ApplicationInfo ai) {
+ private String chooseDriverInternal(Bundle coreSettings, ApplicationInfo ai) {
final String productionDriver = SystemProperties.get(PROPERTY_GFX_DRIVER_PRODUCTION);
final boolean hasProductionDriver = productionDriver != null && !productionDriver.isEmpty();
@@ -828,7 +845,7 @@
/**
* Choose whether the current process should use the builtin or an updated driver.
*/
- private static boolean chooseDriver(
+ private boolean chooseDriver(
Context context, Bundle coreSettings, PackageManager pm, String packageName,
ApplicationInfo ai) {
final String driverPackageName = chooseDriverInternal(coreSettings, ai);
@@ -908,7 +925,7 @@
return null;
}
- private static String getSphalLibraries(Context context, String driverPackageName) {
+ private String getSphalLibraries(Context context, String driverPackageName) {
try {
final Context driverContext =
context.createPackageContext(driverPackageName, Context.CONTEXT_RESTRICTED);
@@ -939,7 +956,13 @@
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
- FileDescriptor rulesFd, long rulesOffset, long rulesLength);
+ String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
+
+ /**
+ * Hint for GraphicsEnvironment that an activity is launching on the process.
+ * Then the app process is allowed to send stats to GpuStats module.
+ */
+ public static native void hintActivityLaunch();
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 1bddc49..13d5f6a 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -673,11 +673,11 @@
* {@link #dataPosition}. This is used to validate that the marshalled
* transaction is intended for the target interface.
*/
- public final void writeInterfaceToken(String interfaceName) {
+ public final void writeInterfaceToken(@NonNull String interfaceName) {
nativeWriteInterfaceToken(mNativePtr, interfaceName);
}
- public final void enforceInterface(String interfaceName) {
+ public final void enforceInterface(@NonNull String interfaceName) {
nativeEnforceInterface(mNativePtr, interfaceName);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ca0981b..e62ad1f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -852,12 +852,11 @@
/**
* Set the priority of a thread, based on Linux priorities.
- *
- * @param tid The identifier of the thread/process to change. It should be
- * the native thread id but not the managed id of {@link java.lang.Thread}.
+ *
+ * @param tid The identifier of the thread/process to change.
* @param priority A Linux priority level, from -20 for highest scheduling
* priority to 19 for lowest scheduling priority.
- *
+ *
* @throws IllegalArgumentException Throws IllegalArgumentException if
* <var>tid</var> does not exist.
* @throws SecurityException Throws SecurityException if your process does
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 9e332e9..06203ff 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -657,16 +657,8 @@
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
- argsForZygote.add("--mount-external-read");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
- argsForZygote.add("--mount-external-write");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
- argsForZygote.add("--mount-external-full");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
- argsForZygote.add("--mount-external-legacy");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
argsForZygote.add("--mount-external-pass-through");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index a79a1cf..4379ce1 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -70,13 +70,6 @@
public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);
/**
- * Notify the mount service that the mount policy for a UID changed.
- * @param uid The UID for which policy changed.
- * @param packageName The package in the UID for making the call.
- */
- public abstract void onExternalStoragePolicyChanged(int uid, String packageName);
-
- /**
* Gets the mount mode to use for a given UID as determined by consultin all
* policies.
*
diff --git a/core/java/android/provider/FontRequest.java b/core/java/android/provider/FontRequest.java
index 34114bc..1f67e8f 100644
--- a/core/java/android/provider/FontRequest.java
+++ b/core/java/android/provider/FontRequest.java
@@ -20,13 +20,14 @@
import com.android.internal.util.Preconditions;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Information about a font request that may be sent to a Font Provider.
+ * @deprecated Use the {@link androidx.core.provider.FontRequest}
*/
+@Deprecated
public final class FontRequest {
private final String mProviderAuthority;
private final String mProviderPackage;
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index fcbda5f..a15f3ae 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -69,7 +69,11 @@
/**
* Utility class to deal with Font ContentProviders.
+ * @deprecated Use the <a href="{@docRoot}jetpack">Jetpack Core Library</a>
+ * {@link androidx.core.provider.FontsContractCompat} for consistent behavior across all
+ * devices.
*/
+@Deprecated
public class FontsContract {
private static final String TAG = "FontsContract";
@@ -79,7 +83,11 @@
* This should point to a real file or shared memory, as the client will mmap the given file
* descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
* client application.
+ *
+ * @deprecated Use the {@link androidx.core.provider.FontsContractCompat.Columns} for consistent
+ * behavior across all devices.
*/
+ @Deprecated
public static final class Columns implements BaseColumns {
// Do not instantiate.
@@ -174,7 +182,11 @@
/**
* Object represent a font entry in the family returned from {@link #fetchFonts}.
+ *
+ * @deprecated Use the {@link androidx.core.provider.FontsContractCompat.FontInfo} for
+ * consistent behavior across all devices
*/
+ @Deprecated
public static class FontInfo {
private final Uri mUri;
private final int mTtcIndex;
@@ -251,7 +263,11 @@
/**
* Object returned from {@link #fetchFonts}.
+ *
+ * @deprecated Use the {@link androidx.core.provider.FontsContractCompat.FontFamilyResult} for
+ * consistent behavior across all devices
*/
+ @Deprecated
public static class FontFamilyResult {
/**
* Constant represents that the font was successfully retrieved. Note that when this value
@@ -412,7 +428,11 @@
/**
* Interface used to receive asynchronously fetched typefaces.
+ *
+ * @deprecated Use the {@link androidx.core.provider.FontsContractCompat.FontRequestCallback}
+ * for consistent behavior across all devices
*/
+ @Deprecated
public static class FontRequestCallback {
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e978608..97acd2f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3567,6 +3567,9 @@
if (outConfig.fontScale < 0) {
outConfig.fontScale = DEFAULT_FONT_SCALE;
}
+ outConfig.forceBoldText = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.FORCE_BOLD_TEXT, Configuration.FORCE_BOLD_TEXT_NO,
+ userHandle);
final String localeValue =
Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle);
@@ -3597,6 +3600,7 @@
if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
inoutConfig.clearLocales();
}
+ inoutConfig.forceBoldText = Configuration.FORCE_BOLD_TEXT_UNDEFINED;
}
/**
@@ -3620,7 +3624,11 @@
DEFAULT_OVERRIDEABLE_BY_RESTORE);
}
- /** @hide */
+ /**
+ * Convenience function for checking if settings should be overwritten with config changes.
+ * @see #putConfigurationForUser(ContentResolver, Configuration, int)
+ * @hide
+ */
public static boolean hasInterestingConfigurationChanges(int changes) {
return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 ||
(changes & ActivityInfo.CONFIG_LOCALE) != 0;
@@ -12329,6 +12337,15 @@
"angle_allowlist";
/**
+ * Lists of ANGLE EGL features for debugging.
+ * Each list of features is separated by a comma, each feature in each list is separated by
+ * a colon.
+ * e.g. feature1:feature2:feature3,feature1:feature3:feature5
+ * @hide
+ */
+ public static final String ANGLE_EGL_FEATURES = "angle_egl_features";
+
+ /**
* Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
* The value is a boolean (1 or 0).
* @hide
@@ -13398,15 +13415,6 @@
"power_button_very_long_press";
/**
- * Global settings that shouldn't be persisted.
- *
- * @hide
- */
- public static final String[] TRANSIENT_SETTINGS = {
- LOCATION_GLOBAL_KILL_SWITCH,
- };
-
- /**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 042808a4..e520d7c 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -181,6 +181,7 @@
private long mFrameIntervalNanos;
private boolean mDebugPrintNextFrameTimeDelta;
private int mFPSDivisor = 1;
+ private long mLastVsyncId = FrameInfo.INVALID_VSYNC_ID;
/**
* Contains information about the current frame for jank-tracking,
@@ -654,6 +655,18 @@
}
}
+ /**
+ * Returns the vsync id of the last frame callback. Client are expected to call
+ * this function from their frame callback function to get the vsyncId and pass
+ * it together with a buffer or transaction to the Surface Composer. Calling
+ * this function from anywhere else will return an undefined value.
+ *
+ * @hide
+ */
+ public long getVsyncId() {
+ return mLastVsyncId;
+ }
+
void setFPSDivisor(int divisor) {
if (divisor <= 0) divisor = 1;
mFPSDivisor = divisor;
@@ -713,6 +726,7 @@
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, frameTimelineVsyncId);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
+ mLastVsyncId = frameTimelineVsyncId;
}
try {
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 5c08fb1..e3129b6 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -33,6 +33,7 @@
import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
import android.annotation.IntDef;
+import android.app.PictureInPictureParams;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Point;
@@ -185,11 +186,20 @@
@UnsupportedAppUsage
public boolean isNotInRecents;
+ /**
+ * {@link PictureInPictureParams} to allow launcher to determine if an app should
+ * automatically enter PiP on swiping up to home.
+ *
+ * TODO: add this to proto dump
+ */
+ public PictureInPictureParams pictureInPictureParams;
+
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
Rect localBounds, Rect screenSpaceBounds,
WindowConfiguration windowConfig, boolean isNotInRecents,
- SurfaceControl startLeash, Rect startBounds) {
+ SurfaceControl startLeash, Rect startBounds,
+ PictureInPictureParams pictureInPictureParams) {
this.mode = mode;
this.taskId = taskId;
this.leash = leash;
@@ -205,6 +215,7 @@
this.isNotInRecents = isNotInRecents;
this.startLeash = startLeash;
this.startBounds = startBounds == null ? null : new Rect(startBounds);
+ this.pictureInPictureParams = pictureInPictureParams;
}
public RemoteAnimationTarget(Parcel in) {
@@ -223,6 +234,7 @@
isNotInRecents = in.readBoolean();
startLeash = in.readParcelable(null);
startBounds = in.readParcelable(null);
+ pictureInPictureParams = in.readParcelable(null);
}
@Override
@@ -247,6 +259,7 @@
dest.writeBoolean(isNotInRecents);
dest.writeParcelable(startLeash, 0 /* flags */);
dest.writeParcelable(startBounds, 0 /* flags */);
+ dest.writeParcelable(pictureInPictureParams, 0 /* flags */);
}
public void dump(PrintWriter pw, String prefix) {
@@ -263,6 +276,7 @@
pw.println();
pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
pw.print(prefix); pw.print("leash="); pw.println(leash);
+ pw.print(prefix); pw.print("pictureInPictureParams="); pw.println(pictureInPictureParams);
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c698b92..0c64eea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -182,9 +182,6 @@
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long transactionObj, long nativeObject,
long barrierObject, long frame);
- private static native void nativeDeferTransactionUntilSurface(long transactionObj,
- long nativeObject,
- long surfaceObject, long frame);
private static native void nativeReparentChildren(long transactionObj, long nativeObject,
long newParentObject);
private static native void nativeReparent(long transactionObj, long nativeObject,
@@ -225,6 +222,8 @@
int transformHint);
private static native void nativeSetFocusedWindow(long transactionObj, IBinder toToken,
IBinder focusedToken, int displayId);
+ private static native void nativeSetFrameTimelineVsync(long transactionObj,
+ long frameTimelineVsyncId);
@Nullable
@GuardedBy("mLock")
@@ -2945,22 +2944,6 @@
/**
* @hide
*/
- @Deprecated
- @UnsupportedAppUsage
- public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
- long frameNumber) {
- if (frameNumber < 0) {
- return this;
- }
- checkPreconditions(sc);
- nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
- barrierSurface.mNativeObject, frameNumber);
- return this;
- }
-
- /**
- * @hide
- */
public Transaction reparentChildren(SurfaceControl sc, SurfaceControl newParent) {
checkPreconditions(sc);
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParent.mNativeObject);
@@ -3341,6 +3324,19 @@
}
/**
+ * Sets the frame timeline vsync id received from choreographer
+ * {@link Choreographer#getVsyncId()} that corresponds to the transaction submitted on that
+ * surface control.
+ *
+ * @hide
+ */
+ @NonNull
+ public Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
+ nativeSetFrameTimelineVsync(mNativeObject, frameTimelineVsyncId);
+ return this;
+ }
+
+ /**
* Writes the transaction to parcel, clearing the transaction as if it had been applied so
* it can be used to store future transactions. It's the responsibility of the parcel
* reader to apply the original transaction.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a8ec9ed..78c71b8 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1245,7 +1245,7 @@
* of the old SurfaceControl alive.
*/
private SurfaceControl createSurfaceControls(ViewRootImpl viewRoot) {
- final String name = "SurfaceView - " + viewRoot.getTitle().toString();
+ final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession)
.setName(name)
@@ -1270,7 +1270,7 @@
.setBLASTLayer()
.setCallsite("SurfaceView.updateSurface")
.build();
- mBlastBufferQueue = new BLASTBufferQueue(
+ mBlastBufferQueue = new BLASTBufferQueue(name,
mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, true /* TODO */);
} else {
previousSurfaceControl = mSurfaceControl;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 778ebb0..e00ff7e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -78,6 +78,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.INSETS_CONTROLLER;
@@ -1826,7 +1827,7 @@
Surface ret = null;
if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue(
+ mBlastBufferQueue = new BLASTBufferQueue(mTag,
mBlastSurfaceControl, width, height, mEnableTripleBuffering);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
@@ -2707,7 +2708,13 @@
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
- surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
+ // When using Blast, the surface generation id may not change when there's a new
+ // SurfaceControl. In that case, we also check relayout flag
+ // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
+ // SurfaceControl.
+ surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
+ || (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
+ == RELAYOUT_RES_SURFACE_CHANGED)
&& mSurface.isValid();
if (cutoutChanged) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 44c754c..9ba886a 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2465,8 +2465,7 @@
* {@link #STATE_UNKNOWN_COMPAT_MODE} (beucase the session was finished when the URL bar
* changed on compat mode), {@link #STATE_UNKNOWN_FAILED} (because the session was finished
* when the service failed to fullfil the request, or {@link #STATE_DISABLED_BY_SERVICE}
- * (because the autofill service or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill
- * service disabled further autofill requests for the activity).
+ * (because the autofill service disabled further autofill requests for the activity).
* @param autofillableIds list of ids that could trigger autofill, use to not handle a new
* session when they're entered.
*/
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 0535365..16fd383 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -643,54 +643,58 @@
// change should also get get rid of the "internalNotifyXXXX" methods above
void notifyChildSessionStarted(int parentSessionId, int childSessionId,
@NonNull ContentCaptureContext clientContext) {
- sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
.setParentSessionId(parentSessionId).setClientContext(clientContext),
- FORCE_FLUSH);
+ FORCE_FLUSH));
}
void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
- sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
- .setParentSessionId(parentSessionId), FORCE_FLUSH);
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
+ .setParentSessionId(parentSessionId), FORCE_FLUSH));
}
void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
- .setViewNode(node.mNode));
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
+ .setViewNode(node.mNode)));
}
/** Public because is also used by ViewRootImpl */
public void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
+ mHandler.post(() -> sendEvent(
+ new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id)));
}
void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
- .setText(text));
+ mHandler.post(() -> sendEvent(
+ new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED)
+ .setAutofillId(id).setText(text)));
}
/** Public because is also used by ViewRootImpl */
public void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
- .setInsets(viewInsets));
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
+ .setInsets(viewInsets)));
}
/** Public because is also used by ViewRootImpl */
public void notifyViewTreeEvent(int sessionId, boolean started) {
final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
- sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH));
}
void notifySessionResumed(int sessionId) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED), FORCE_FLUSH);
+ mHandler.post(() -> sendEvent(
+ new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED), FORCE_FLUSH));
}
void notifySessionPaused(int sessionId) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED), FORCE_FLUSH);
+ mHandler.post(() -> sendEvent(
+ new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED), FORCE_FLUSH));
}
void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
- .setClientContext(context));
+ mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
+ .setClientContext(context)));
}
@Override
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index b04105a..28496c6 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -44,24 +44,17 @@
}
/**
- * Returns PacProcessor instance associated with the {@link Network}.
- * The host resolution is done on this {@link Network}.
+ * Create a new PacProcessor instance.
*
- * <p> There can only be one {@link PacProcessor} instance at a time for each {@link Network}.
- * This method will create a new instance if one did not already exist, or
- * if the previous instance was released with {@link #releasePacProcessor}.
+ * <p> The created instance needs to be released manually once it is no longer needed
+ * by calling {@link #releasePacProcessor} to prevent memory leaks.
*
- * <p> The {@link PacProcessor} instance needs to be released manually with
- * {@link #releasePacProcessor} when the associated {@link Network} goes away.
- *
- * @param network a {@link Network} which this {@link PacProcessor}
- * will use for host/address resolution.
- * If {@code null} this method is equivalent to {@link #getInstance}.
- * @return {@link PacProcessor} instance for the specified network.
+ * <p> The created instance is not tied to any particular {@link Network}.
+ * To associate {@link PacProcessor} with a {@link Network} use {@link #setNetwork} method.
*/
@NonNull
- static PacProcessor getInstanceForNetwork(@Nullable Network network) {
- return WebViewFactory.getProvider().getPacProcessorForNetwork(network);
+ static PacProcessor createInstance() {
+ throw new UnsupportedOperationException("Not implemented");
}
/**
@@ -94,6 +87,18 @@
}
/**
+ * Associate {@link PacProcessor} instance with the {@link Network}.
+ * Once this method returns host resolution is done on the set {@link Network}.
+
+ * @param network a {@link Network} which this {@link PacProcessor}
+ * will use for host/address resolution. If {@code null} reset
+ * {@link PacProcessor} instance so it is not associated with any {@link Network}.
+ */
+ default void setNetwork(@Nullable Network network) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
* Returns a {@link Network} associated with this {@link PacProcessor}.
*
* @return an associated {@link Network} or {@code null} if a network is unspecified.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 052bca5..8eb1371 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -704,18 +704,20 @@
return mProvider.restoreState(inState);
}
- /**
- * Loads the given URL with the specified additional HTTP headers.
+ /**
+ * Loads the given URL with additional HTTP headers, specified as a map from
+ * name to value. Note that if this map contains any of the headers that are
+ * set by default by this WebView, such as those controlling caching, accept
+ * types or the User-Agent, their values may be overridden by this WebView's
+ * defaults.
+ * <p>
+ * Some older WebView implementations require {@code additionalHttpHeaders}
+ * to be mutable.
* <p>
* Also see compatibility note on {@link #evaluateJavascript}.
*
* @param url the URL of the resource to load
- * @param additionalHttpHeaders the additional headers to be used in the
- * HTTP request for this URL, specified as a map from name to
- * value. Note that if this map contains any of the headers
- * that are set by default by this WebView, such as those
- * controlling caching, accept types or the User-Agent, their
- * values may be overridden by this WebView's defaults.
+ * @param additionalHttpHeaders map with additional headers
*/
public void loadUrl(@NonNull String url, @NonNull Map<String, String> additionalHttpHeaders) {
checkThread();
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index ce999cd..3d64506 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -17,7 +17,6 @@
package android.webkit;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -186,8 +185,7 @@
}
/**
- * Returns PacProcessor instance associated with the {@link Network}.
- * The host resolution is done on this {@link Network}.
+ * Create a new PacProcessor instance.
*
* @param network a {@link Network} which needs to be associated
* with the returned {@link PacProcessor}.
@@ -195,7 +193,7 @@
* @return the {@link PacProcessor} instance associated with {@link Network}.
*/
@NonNull
- default PacProcessor getPacProcessorForNetwork(@Nullable Network network) {
+ default PacProcessor createPacProcessor() {
throw new UnsupportedOperationException("Not implemented");
}
diff --git a/core/java/android/window/ITransitionPlayer.aidl b/core/java/android/window/ITransitionPlayer.aidl
new file mode 100644
index 0000000..a8a29b2
--- /dev/null
+++ b/core/java/android/window/ITransitionPlayer.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+import android.window.WindowContainerTransaction;
+
+/**
+ * Implemented by WMShell to initiate and play transition animations.
+ * The flow (with {@link IWindowOrganizerController}) looks like this:
+ * <p><ol>
+ * <li>Core starts an activity and calls {@link #requestStartTransition}
+ * <li>This TransitionPlayer impl does whatever, then calls
+ * {@link IWindowOrganizerController#startTransition} to tell Core to formally start (until
+ * this happens, Core will collect changes on the transition, but won't consider it ready to
+ * animate).
+ * <li>Once all collected changes on the transition have finished drawing, Core will then call
+ * {@link #onTransitionReady} here to delegate the actual animation.
+ * <li>Once this TransitionPlayer impl finishes animating, it notifies Core via
+ * {@link IWindowOrganizerController#finishTransition}. At this point, ITransitionPlayer's
+ * responsibilities end.
+ * </ul>
+ *
+ * {@hide}
+ */
+oneway interface ITransitionPlayer {
+
+ /**
+ * Called when all participants of a transition are ready to animate. This is in response to
+ * {@link IWindowOrganizerController#startTransition}.
+ *
+ * @param transitionToken An identifying token for the transition that is now ready to animate.
+ * @param info A collection of all the changes encapsulated by this transition.
+ * @param t A surface transaction containing the surface state prior to animating.
+ */
+ void onTransitionReady(in IBinder transitionToken, in TransitionInfo info,
+ in SurfaceControl.Transaction t);
+
+ /**
+ * Called when something in WMCore requires a transition to play -- for example when an Activity
+ * is started in a new Task.
+ *
+ * @param type The {@link WindowManager#TransitionType} of the transition to start.
+ * @param transitionToken An identifying token for the transition that needs to be started.
+ * Pass this to {@link IWindowOrganizerController#startTransition}.
+ */
+ void requestStartTransition(int type, in IBinder transitionToken);
+}
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index 7e9c783..0cd9b36 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -18,8 +18,10 @@
import android.view.SurfaceControl;
+import android.os.IBinder;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskOrganizerController;
+import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -45,6 +47,30 @@
int applySyncTransaction(in WindowContainerTransaction t,
in IWindowContainerTransactionCallback callback);
+ /**
+ * Starts a transition.
+ * @param type The transition type.
+ * @param transitionToken A token associated with the transition to start. If null, a new
+ * transition will be created of the provided type.
+ * @param t Operations that are part of the transition.
+ * @return a token representing the transition. This will just be transitionToken if it was
+ * non-null.
+ */
+ IBinder startTransition(int type, in @nullable IBinder transitionToken,
+ in @nullable WindowContainerTransaction t);
+
+ /**
+ * Finishes a transition. This must be called for all created transitions.
+ * @param transitionToken Which transition to finish
+ * @param t Changes to make before finishing but in the same SF Transaction. Can be null.
+ * @param callback Called when t is finished applying.
+ * @return An ID for the sync operation (see {@link #applySyncTransaction}. This will be
+ * negative if no sync transaction was attached (null t or callback)
+ */
+ int finishTransition(in IBinder transitionToken,
+ in @nullable WindowContainerTransaction t,
+ in IWindowContainerTransactionCallback callback);
+
/** @return An interface enabling the management of task organizers. */
ITaskOrganizerController getTaskOrganizerController();
@@ -61,4 +87,10 @@
* @return true if the screenshot was successful, false otherwise.
*/
boolean takeScreenshot(in WindowContainerToken token, out SurfaceControl outSurfaceControl);
+
+ /**
+ * Registers a transition player with Core. There is only one of these at a time and calling
+ * this will replace the existing one if set.
+ */
+ void registerTransitionPlayer(in ITransitionPlayer player);
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl b/core/java/android/window/TransitionInfo.aidl
similarity index 87%
copy from core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
copy to core/java/android/window/TransitionInfo.aidl
index 62240ba..6c33e97 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
+++ b/core/java/android/window/TransitionInfo.aidl
@@ -14,6 +14,7 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.window;
-parcelable TimeZoneConfiguration;
+parcelable TransitionInfo;
+parcelable TransitionInfo.Change;
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
new file mode 100644
index 0000000..34d1d4e
--- /dev/null
+++ b/core/java/android/window/TransitionInfo.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Used to communicate information about what is changing during a transition to a TransitionPlayer.
+ * @hide
+ */
+public final class TransitionInfo implements Parcelable {
+
+ /** No transition mode. This is a placeholder, don't use this as an actual mode. */
+ public static final int TRANSIT_NONE = 0;
+
+ /** The container didn't exist before but will exist and be visible after. */
+ public static final int TRANSIT_OPEN = 1;
+
+ /** The container existed and was visible before but won't exist after. */
+ public static final int TRANSIT_CLOSE = 2;
+
+ /** The container existed before but was invisible and will be visible after. */
+ public static final int TRANSIT_SHOW = 3;
+
+ /** The container is going from visible to invisible but it will still exist after. */
+ public static final int TRANSIT_HIDE = 4;
+
+ /** The container exists and is visible before and after but it changes. */
+ public static final int TRANSIT_CHANGE = 5;
+
+ /** @hide */
+ @IntDef(prefix = { "TRANSIT_" }, value = {
+ TRANSIT_NONE,
+ TRANSIT_OPEN,
+ TRANSIT_CLOSE,
+ TRANSIT_SHOW,
+ TRANSIT_HIDE,
+ TRANSIT_CHANGE
+ })
+ public @interface TransitionMode {}
+
+ private final @WindowManager.TransitionType int mType;
+ private final ArrayList<Change> mChanges = new ArrayList<>();
+
+ /** @hide */
+ public TransitionInfo(@WindowManager.TransitionType int type) {
+ mType = type;
+ }
+
+ private TransitionInfo(Parcel in) {
+ mType = in.readInt();
+ in.readList(mChanges, null /* classLoader */);
+ }
+
+ @Override
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeList(mChanges);
+ }
+
+ @NonNull
+ public static final Creator<TransitionInfo> CREATOR =
+ new Creator<TransitionInfo>() {
+ @Override
+ public TransitionInfo createFromParcel(Parcel in) {
+ return new TransitionInfo(in);
+ }
+
+ @Override
+ public TransitionInfo[] newArray(int size) {
+ return new TransitionInfo[size];
+ }
+ };
+
+ @Override
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ @NonNull
+ public List<Change> getChanges() {
+ return mChanges;
+ }
+
+ /**
+ * @return the Change that a window is undergoing or {@code null} if not directly
+ * represented.
+ */
+ @Nullable
+ public Change getChange(@NonNull WindowContainerToken token) {
+ for (int i = mChanges.size() - 1; i >= 0; --i) {
+ if (mChanges.get(i).mContainer == token) {
+ return mChanges.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add a {@link Change} to this transition.
+ */
+ public void addChange(@NonNull Change change) {
+ mChanges.add(change);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{t=" + mType + " c=[");
+ for (int i = 0; i < mChanges.size(); ++i) {
+ if (i > 0) {
+ sb.append(',');
+ }
+ sb.append(mChanges.get(i));
+ }
+ sb.append("]}");
+ return sb.toString();
+ }
+
+ /** Converts a transition mode/action to its string representation. */
+ @NonNull
+ public static String modeToString(@TransitionMode int mode) {
+ switch(mode) {
+ case TRANSIT_NONE: return "NONE";
+ case TRANSIT_OPEN: return "OPEN";
+ case TRANSIT_CLOSE: return "CLOSE";
+ case TRANSIT_SHOW: return "SHOW";
+ case TRANSIT_HIDE: return "HIDE";
+ case TRANSIT_CHANGE: return "CHANGE";
+ default: return "<unknown:" + mode + ">";
+ }
+ }
+
+ /** Represents the change a WindowContainer undergoes during a transition */
+ public static final class Change implements Parcelable {
+ private final WindowContainerToken mContainer;
+ private WindowContainerToken mParent;
+ private final SurfaceControl mLeash;
+ private int mMode = TRANSIT_NONE;
+ private final Rect mStartBounds = new Rect();
+ private final Rect mEndBounds = new Rect();
+
+ public Change(@NonNull WindowContainerToken container, @NonNull SurfaceControl leash) {
+ mContainer = container;
+ mLeash = leash;
+ }
+
+ private Change(Parcel in) {
+ mContainer = WindowContainerToken.CREATOR.createFromParcel(in);
+ mParent = in.readParcelable(WindowContainerToken.class.getClassLoader());
+ mLeash = new SurfaceControl();
+ mLeash.readFromParcel(in);
+ mMode = in.readInt();
+ mStartBounds.readFromParcel(in);
+ mEndBounds.readFromParcel(in);
+ }
+
+ /** Sets the parent of this change's container. The parent must be a participant or null. */
+ public void setParent(@Nullable WindowContainerToken parent) {
+ mParent = parent;
+ }
+
+ /** Sets the transition mode for this change */
+ public void setMode(@TransitionMode int mode) {
+ mMode = mode;
+ }
+
+ /** Sets the bounds this container occupied before the change */
+ public void setStartBounds(@Nullable Rect rect) {
+ mStartBounds.set(rect);
+ }
+
+ /** Sets the bounds this container will occupy after the change */
+ public void setEndBounds(@Nullable Rect rect) {
+ mEndBounds.set(rect);
+ }
+
+ /** @return the container that is changing */
+ @NonNull
+ public WindowContainerToken getContainer() {
+ return mContainer;
+ }
+
+ /**
+ * @return the parent of the changing container. This is the parent within the participants,
+ * not necessarily the actual parent.
+ */
+ @Nullable
+ public WindowContainerToken getParent() {
+ return mParent;
+ }
+
+ /** @return which action this change represents. */
+ public @TransitionMode int getMode() {
+ return mMode;
+ }
+
+ /**
+ * @return the bounds of the container before the change. It may be empty if the container
+ * is coming into existence.
+ */
+ @NonNull
+ public Rect getStartBounds() {
+ return mStartBounds;
+ }
+
+ /**
+ * @return the bounds of the container after the change. It may be empty if the container
+ * is disappearing.
+ */
+ @NonNull
+ public Rect getEndBounds() {
+ return mEndBounds;
+ }
+
+ /** @return the leash or surface to animate for this container */
+ @NonNull
+ public SurfaceControl getLeash() {
+ return mLeash;
+ }
+
+ @Override
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ mContainer.writeToParcel(dest, flags);
+ dest.writeParcelable(mParent, 0);
+ mLeash.writeToParcel(dest, flags);
+ dest.writeInt(mMode);
+ mStartBounds.writeToParcel(dest, flags);
+ mEndBounds.writeToParcel(dest, flags);
+ }
+
+ @NonNull
+ public static final Creator<Change> CREATOR =
+ new Creator<Change>() {
+ @Override
+ public Change createFromParcel(Parcel in) {
+ return new Change(in);
+ }
+
+ @Override
+ public Change[] newArray(int size) {
+ return new Change[size];
+ }
+ };
+
+ @Override
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+ + " m=" + modeToString(mMode) + " sb=" + mStartBounds
+ + " eb=" + mEndBounds + "}";
+ }
+ }
+}
diff --git a/core/java/android/window/WindowContainerToken.java b/core/java/android/window/WindowContainerToken.java
index c92ccae..96e8b44 100644
--- a/core/java/android/window/WindowContainerToken.java
+++ b/core/java/android/window/WindowContainerToken.java
@@ -78,6 +78,11 @@
}
@Override
+ public String toString() {
+ return "WCT{" + mRealToken + "}";
+ }
+
+ @Override
public boolean equals(Object obj) {
if (!(obj instanceof WindowContainerToken)) {
return false;
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 97a97d9..5ac19fa 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -19,8 +19,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityTaskManager;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Singleton;
import android.view.SurfaceControl;
@@ -66,6 +68,48 @@
}
/**
+ * Start a transition.
+ * @param type The type of the transition. This is ignored if a transitionToken is provided.
+ * @param transitionToken An existing transition to start. If null, a new transition is created.
+ * @param t The set of window operations that are part of this transition.
+ * @return A token identifying the transition. This will be the same as transitionToken if it
+ * was provided.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ @NonNull
+ public IBinder startTransition(int type, @Nullable IBinder transitionToken,
+ @Nullable WindowContainerTransaction t) {
+ try {
+ return getWindowOrganizerController().startTransition(type, transitionToken, t);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Finishes a running transition.
+ * @param transitionToken The transition to finish. Can't be null.
+ * @param t A set of window operations to apply before finishing.
+ * @param callback A sync callback (if provided). See {@link #applySyncTransaction}.
+ * @return An ID for the sync operation if performed. See {@link #applySyncTransaction}.
+ *
+ * @hide
+ */
+ @SuppressLint("ExecutorRegistration")
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public int finishTransition(@NonNull IBinder transitionToken,
+ @Nullable WindowContainerTransaction t,
+ @Nullable WindowContainerTransactionCallback callback) {
+ try {
+ return getWindowOrganizerController().finishTransition(transitionToken, t,
+ callback != null ? callback.mInterface : null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Take a screenshot for a specified Window
* @param token The token for the WindowContainer that should get a screenshot taken.
* @return A SurfaceControl where the screenshot will be attached, or null if failed.
@@ -87,6 +131,19 @@
}
}
+ /**
+ * Register an ITransitionPlayer to handle transition animations.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void registerTransitionPlayer(@Nullable ITransitionPlayer player) {
+ try {
+ getWindowOrganizerController().registerTransitionPlayer(player);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();
diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl b/core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl
similarity index 100%
rename from core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 900e18d..28a9601 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -166,7 +166,7 @@
// Now fetch app icon and raster with no badging even in work profile
Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
- .getIconBitmap(UserHandle.getUserHandleForUid(UserHandle.myUserId()));
+ .getIconBitmap(android.os.Process.myUserHandle());
// Raster target drawable with appIcon as a badge
SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index e60f7fc..dd4409c 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -44,26 +44,37 @@
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
// Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
- public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 1;
- public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 0;
- public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 0;
- public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 0;
- public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 0;
- public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 0;
- public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 0;
- public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS = 0;
- public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON = 0;
- public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 0;
- public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 0;
- public static final int CUJ_LAUNCHER_QUICK_SWITCH = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 1;
+ public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 2;
+ public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 3;
+ public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 4;
+ public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 5;
+ public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 6;
+ public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS = 7;
+ public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON = 8;
+ public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 9;
+ public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 10;
+ public static final int CUJ_LAUNCHER_QUICK_SWITCH = 11;
private static final int NO_STATSD_LOGGING = -1;
// Used to convert CujType to InteractionType enum value for statsd logging.
// Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd.
- private static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
- NO_STATSD_LOGGING,
+ @VisibleForTesting
+ public static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
+ NO_STATSD_LOGGING,
};
private static volatile InteractionJankMonitor sInstance;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 095882e..60f1b44 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -36,7 +36,6 @@
import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.RuntimeHooks;
-import dalvik.system.ThreadPrioritySetter;
import dalvik.system.VMRuntime;
import libcore.content.type.MimeMap;
@@ -208,7 +207,6 @@
*/
public static void preForkInit() {
if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
- RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
RuntimeInit.enableDdms();
// TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
// MimeMap.setDefault(DefaultMimeMapFactory.create());
@@ -221,35 +219,6 @@
MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
}
- private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter {
- // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc
- private static final int[] NICE_VALUES = {
- Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY)
- Process.THREAD_PRIORITY_BACKGROUND + 6,
- Process.THREAD_PRIORITY_BACKGROUND + 3,
- Process.THREAD_PRIORITY_BACKGROUND,
- Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY)
- Process.THREAD_PRIORITY_DEFAULT - 2,
- Process.THREAD_PRIORITY_DEFAULT - 4,
- Process.THREAD_PRIORITY_URGENT_DISPLAY + 3,
- Process.THREAD_PRIORITY_URGENT_DISPLAY + 2,
- Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY)
- };
-
- @Override
- public void setPriority(int nativeTid, int priority) {
- // Check NICE_VALUES[] length first.
- if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) {
- throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length);
- }
- // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10).
- if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
- throw new IllegalArgumentException("Priority out of range: " + priority);
- }
- Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]);
- }
- }
-
@UnsupportedAppUsage
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index a985965..5e20cd0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -172,23 +172,11 @@
public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
/** Default external storage should be mounted. */
public static final int MOUNT_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT;
- /** Read-only external storage should be mounted. */
- public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ;
- /** Read-write external storage should be mounted. */
- public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
- /**
- * Mount mode for apps that are already installed on the device before the isolated_storage
- * feature is enabled.
- */
- public static final int MOUNT_EXTERNAL_LEGACY = IVold.REMOUNT_MODE_LEGACY;
/**
* Mount mode for package installers which should give them access to
* all obb dirs in addition to their package sandboxes
*/
public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
- /** Read-write external storage should be mounted instead of package sandbox */
- public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL;
-
/** The lower file system should be bind mounted directly on external storage */
public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index ed07432..32b808a 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -380,16 +380,8 @@
mNiceName = getAssignmentValue(arg);
} else if (arg.equals("--mount-external-default")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
- } else if (arg.equals("--mount-external-read")) {
- mMountExternal = Zygote.MOUNT_EXTERNAL_READ;
- } else if (arg.equals("--mount-external-write")) {
- mMountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
- } else if (arg.equals("--mount-external-full")) {
- mMountExternal = Zygote.MOUNT_EXTERNAL_FULL;
- } else if (arg.equals("--mount-external-installer")) {
+ } else if (arg.equals("--mount-external-installer")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
- } else if (arg.equals("--mount-external-legacy")) {
- mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
} else if (arg.equals("--mount-external-pass-through")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
} else if (arg.equals("--mount-external-android-writable")) {
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 9874c6a..ce3efd3 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -48,6 +48,10 @@
Consts.TAG_WM),
WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
+ WM_DEBUG_STATES(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
@@ -74,6 +78,8 @@
Consts.TAG_WM),
WM_DEBUG_SYNC_ENGINE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
+ WM_DEBUG_WINDOW_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index cc2934f..caae518 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -242,4 +242,10 @@
* @param connect {@code true} if needs connection, otherwise set the connection to null.
*/
void requestWindowMagnificationConnection(boolean connect);
+
+ /**
+ * Allow for pass-through arguments from `adb shell cmd statusbar <args>`, and write to the
+ * file descriptor passed in.
+ */
+ void passThroughShellCommand(in String[] args, in ParcelFileDescriptor pfd);
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index cd69a02..f317f3f 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -760,6 +760,7 @@
/**
* Returns an array containing elements from the given one that match the given predicate.
+ * The returned array may, in some cases, be the reference to the input array.
*/
public static @Nullable <T> T[] filter(@Nullable T[] items,
@NonNull IntFunction<T[]> arrayConstructor,
@@ -775,16 +776,13 @@
matchesCount++;
}
}
- if (matchesCount == 0) {
- return items;
- }
if (matchesCount == items.length) {
return items;
}
- if (matchesCount == 0) {
- return null;
- }
T[] result = arrayConstructor.apply(matchesCount);
+ if (matchesCount == 0) {
+ return result;
+ }
int outIdx = 0;
for (int i = 0; i < size; i++) {
if (predicate.test(items[i])) {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 396a84f..ed663cf 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -46,6 +46,7 @@
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -55,7 +56,6 @@
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
-import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -95,7 +95,7 @@
private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
- int[] mGlobalGids;
+ int[] mGlobalGids = EmptyArray.INT;
// These are the built-in uid -> permission mappings that were read from the
// system configuration files.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b4b58ff..adb0fad 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -317,4 +317,9 @@
cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
},
},
+
+ // Workaround Clang LTO crash.
+ lto: {
+ never: true,
+ },
}
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 23f4325..a30c37b 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -29,10 +29,21 @@
namespace android {
-static jlong nativeCreate(JNIEnv* env, jclass clazz, jlong surfaceControl, jlong width, jlong height,
- jboolean enableTripleBuffering) {
- sp<BLASTBufferQueue> queue = new BLASTBufferQueue(
- reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, enableTripleBuffering);
+static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,
+ jlong width, jlong height, jboolean enableTripleBuffering) {
+ String8 str8;
+ if (jName) {
+ const jchar* str16 = env->GetStringCritical(jName, nullptr);
+ if (str16) {
+ str8 = String8(reinterpret_cast<const char16_t*>(str16), env->GetStringLength(jName));
+ env->ReleaseStringCritical(jName, str16);
+ str16 = nullptr;
+ }
+ }
+ std::string name = str8.string();
+ sp<BLASTBufferQueue> queue =
+ new BLASTBufferQueue(name, reinterpret_cast<SurfaceControl*>(surfaceControl), width,
+ height, enableTripleBuffering);
queue->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(queue.get());
}
@@ -59,18 +70,12 @@
}
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "nativeCreate", "(JJJZ)J",
- (void*)nativeCreate },
- { "nativeGetSurface", "(J)Landroid/view/Surface;",
- (void*)nativeGetSurface },
- { "nativeDestroy", "(J)V",
- (void*)nativeDestroy },
- { "nativeSetNextTransaction", "(JJ)V",
- (void*)nativeSetNextTransaction },
- { "nativeUpdate", "(JJJJ)V",
- (void*)nativeUpdate }
-};
+ /* name, signature, funcPtr */
+ {"nativeCreate", "(Ljava/lang/String;JJJZ)J", (void*)nativeCreate},
+ {"nativeGetSurface", "(J)Landroid/view/Surface;", (void*)nativeGetSurface},
+ {"nativeDestroy", "(J)V", (void*)nativeDestroy},
+ {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
+ {"nativeUpdate", "(JJJJ)V", (void*)nativeUpdate}};
int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue",
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 859b40a..919e351 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -249,6 +249,16 @@
return metadata->entryCount();
}
+static jlong CameraMetadata_getBufferSize(JNIEnv *env, jclass thiz, jlong ptr) {
+ ALOGV("%s", __FUNCTION__);
+
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
+
+ if (metadata == NULL) return 0;
+
+ return metadata->bufferSize();
+}
+
// idempotent. calling more than once has no effect.
static void CameraMetadata_close(JNIEnv *env, jclass thiz, jlong ptr) {
ALOGV("%s", __FUNCTION__);
@@ -561,6 +571,9 @@
{ "nativeGetEntryCount",
"(J)I",
(void*)CameraMetadata_getEntryCount },
+ { "nativeGetBufferSize",
+ "(J)J",
+ (void*)CameraMetadata_getBufferSize },
{ "nativeClose",
"(J)V",
(void*)CameraMetadata_close },
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 4f3f283..b40491a 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "GraphicsEnvironment"
+#include <vector>
+
#include <graphicsenv/GraphicsEnv.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativeloader/native_loader.h>
@@ -47,16 +49,36 @@
appPackageNameChars.c_str(), vulkanVersion);
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn,
- jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
+ jstring devOptIn, jobjectArray featuresObj, jobject rulesFd,
+ jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars devOptInChars(env, devOptIn);
+ std::vector<std::string> features;
+ if (featuresObj != nullptr) {
+ jsize length = env->GetArrayLength(featuresObj);
+ for (jsize i = 0; i < length; ++i) {
+ jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(featuresObj, i));
+ // null entries are ignored
+ if (jstr == nullptr) {
+ continue;
+ }
+ const char* cstr = env->GetStringUTFChars(jstr, nullptr);
+ if (cstr == nullptr) {
+ continue;
+ }
+ features.emplace_back(cstr);
+ env->ReleaseStringUTFChars(jstr, cstr);
+ }
+ }
+
int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength);
+ devOptInChars.c_str(), features,
+ rulesFd_native, rulesOffset, rulesLength);
}
bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -94,16 +116,25 @@
}
const JNINativeMethod g_methods[] = {
- { "isDebuggable", "()Z", reinterpret_cast<void*>(isDebuggable_native) },
- { "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native) },
- { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V", reinterpret_cast<void*>(setGpuStats_native) },
- { "setInjectLayersPrSetDumpable", "()Z", reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native) },
- { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
- { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
- { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
- { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
- { "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
- { "hintActivityLaunch", "()V", reinterpret_cast<void*>(hintActivityLaunch_native) },
+ {"isDebuggable", "()Z", reinterpret_cast<void*>(isDebuggable_native)},
+ {"setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V",
+ reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native)},
+ {"setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V",
+ reinterpret_cast<void*>(setGpuStats_native)},
+ {"setInjectLayersPrSetDumpable", "()Z",
+ reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
+ {"setAngleInfo",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/io/"
+ "FileDescriptor;JJ)V",
+ reinterpret_cast<void*>(setAngleInfo_native)},
+ {"getShouldUseAngle", "(Ljava/lang/String;)Z",
+ reinterpret_cast<void*>(shouldUseAngle_native)},
+ {"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
+ reinterpret_cast<void*>(setLayerPaths_native)},
+ {"setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native)},
+ {"setDebugLayersGLES", "(Ljava/lang/String;)V",
+ reinterpret_cast<void*>(setDebugLayersGLES_native)},
+ {"hintActivityLaunch", "()V", reinterpret_cast<void*>(hintActivityLaunch_native)},
};
const char* const kGraphicsEnvironmentName = "android/os/GraphicsEnvironment";
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0892b70..355ef0c 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -612,50 +612,77 @@
return ret;
}
+// String tries to allocate itself on the stack, within a known size, but will
+// make a heap allocation if not.
+template <size_t StackReserve>
+class StackString {
+public:
+ StackString(JNIEnv* env, jstring str) : mEnv(env), mJStr(str) {
+ LOG_ALWAYS_FATAL_IF(str == nullptr);
+ mSize = env->GetStringLength(str);
+ if (mSize > StackReserve) {
+ mStr = new jchar[mSize];
+ } else {
+ mStr = &mBuffer[0];
+ }
+ mEnv->GetStringRegion(str, 0, mSize, mStr);
+ }
+ ~StackString() {
+ if (mStr != &mBuffer[0]) {
+ delete[] mStr;
+ }
+ }
+ const jchar* str() { return mStr; }
+ jsize size() { return mSize; }
+
+private:
+ JNIEnv* mEnv;
+ jstring mJStr;
+
+ jchar mBuffer[StackReserve];
+ // pointer to &mBuffer[0] if string fits in mBuffer, otherwise owned
+ jchar* mStr;
+ jsize mSize;
+};
+
+// This size is chosen to be longer than most interface descriptors.
+// Ones longer than this will be allocated on the heap.
+typedef StackString<64> InterfaceDescriptorString;
+
static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jlong nativePtr,
jstring name)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
- if (parcel != NULL) {
- // In the current implementation, the token is just the serialized interface name that
- // the caller expects to be invoking
- const jchar* str = env->GetStringCritical(name, 0);
- if (str != NULL) {
- parcel->writeInterfaceToken(String16(
- reinterpret_cast<const char16_t*>(str),
- env->GetStringLength(name)));
- env->ReleaseStringCritical(name, str);
- }
+ if (parcel != nullptr) {
+ InterfaceDescriptorString descriptor(env, name);
+ parcel->writeInterfaceToken(reinterpret_cast<const char16_t*>(descriptor.str()),
+ descriptor.size());
}
}
static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
- if (parcel != NULL) {
- const jchar* str = env->GetStringCritical(name, 0);
- if (str) {
- IPCThreadState* threadState = IPCThreadState::self();
- const int32_t oldPolicy = threadState->getStrictModePolicy();
- const bool isValid = parcel->enforceInterface(
- reinterpret_cast<const char16_t*>(str),
- env->GetStringLength(name),
- threadState);
- env->ReleaseStringCritical(name, str);
- if (isValid) {
- const int32_t newPolicy = threadState->getStrictModePolicy();
- if (oldPolicy != newPolicy) {
- // Need to keep the Java-level thread-local strict
- // mode policy in sync for the libcore
- // enforcements, which involves an upcall back
- // into Java. (We can't modify the
- // Parcel.enforceInterface signature, as it's
- // pseudo-public, and used via AIDL
- // auto-generation...)
- set_dalvik_blockguard_policy(env, newPolicy);
- }
- return; // everything was correct -> return silently
+ if (parcel != nullptr) {
+ InterfaceDescriptorString descriptor(env, name);
+ IPCThreadState* threadState = IPCThreadState::self();
+ const int32_t oldPolicy = threadState->getStrictModePolicy();
+ const bool isValid =
+ parcel->enforceInterface(reinterpret_cast<const char16_t*>(descriptor.str()),
+ descriptor.size(), threadState);
+ if (isValid) {
+ const int32_t newPolicy = threadState->getStrictModePolicy();
+ if (oldPolicy != newPolicy) {
+ // Need to keep the Java-level thread-local strict
+ // mode policy in sync for the libcore
+ // enforcements, which involves an upcall back
+ // into Java. (We can't modify the
+ // Parcel.enforceInterface signature, as it's
+ // pseudo-public, and used via AIDL
+ // auto-generation...)
+ set_dalvik_blockguard_policy(env, newPolicy);
}
+ return; // everything was correct -> return silently
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9efe4b1..1419855 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -481,7 +481,7 @@
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
auto relative = reinterpret_cast<SurfaceControl *>(relativeToObject);
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- transaction->setRelativeLayer(ctrl, relative->getHandle(), zorder);
+ transaction->setRelativeLayer(ctrl, relative, zorder);
}
static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1327,20 +1327,9 @@
static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jlong barrierObject, jlong frameNumber) {
- auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- auto barrier = reinterpret_cast<SurfaceControl *>(barrierObject);
+ sp<SurfaceControl> ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ sp<SurfaceControl> barrier = reinterpret_cast<SurfaceControl*>(barrierObject);
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- transaction->deferTransactionUntil_legacy(ctrl, barrier->getHandle(), frameNumber);
-}
-
-static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong transactionObj,
- jlong nativeObject,
- jlong surfaceObject, jlong frameNumber) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-
- auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
-
transaction->deferTransactionUntil_legacy(ctrl, barrier, frameNumber);
}
@@ -1351,7 +1340,7 @@
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
auto newParent = reinterpret_cast<SurfaceControl *>(newParentObject);
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- transaction->reparentChildren(ctrl, newParent->getHandle());
+ transaction->reparentChildren(ctrl, newParent);
}
static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1360,7 +1349,7 @@
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
auto newParent = reinterpret_cast<SurfaceControl *>(newParentObject);
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- transaction->reparent(ctrl, newParent != NULL ? newParent->getHandle() : NULL);
+ transaction->reparent(ctrl, newParent);
}
static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1434,7 +1423,8 @@
doThrowNPE(env);
return 0;
}
- sp<SurfaceControl> surface = SurfaceControl::readFromParcel(parcel);
+ sp<SurfaceControl> surface;
+ SurfaceControl::readFromParcel(*parcel, &surface);
if (surface == nullptr) {
return 0;
}
@@ -1462,7 +1452,7 @@
}
SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
if (self != nullptr) {
- self->writeToParcel(parcel);
+ self->writeToParcel(*parcel);
}
}
@@ -1557,6 +1547,13 @@
displayId);
}
+static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong frameTimelineVsyncId) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ transaction->setFrameTimelineVsync(frameTimelineVsyncId);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1691,8 +1688,6 @@
(void*)nativeGetProtectedContentSupport },
{"nativeDeferTransactionUntil", "(JJJJ)V",
(void*)nativeDeferTransactionUntil },
- {"nativeDeferTransactionUntilSurface", "(JJJJ)V",
- (void*)nativeDeferTransactionUntilSurface },
{"nativeReparentChildren", "(JJJ)V",
(void*)nativeReparentChildren } ,
{"nativeReparent", "(JJJ)V",
@@ -1741,6 +1736,8 @@
(void*)nativeSetFixedTransformHint},
{"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Landroid/os/IBinder;I)V",
(void*)nativeSetFocusedWindow},
+ {"nativeSetFrameTimelineVsync", "(JJ)V",
+ (void*)nativeSetFrameTimelineVsync },
// clang-format on
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index e6bfecc..42aab6a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -326,31 +326,15 @@
static FileDescriptorTable* gOpenFdTable = nullptr;
// Must match values in com.android.internal.os.Zygote.
-// The order of entries here must be kept in sync with ExternalStorageViews array values.
+// Note that there are gaps in the constants:
+// This is to further keep the values consistent with IVold.aidl
enum MountExternalKind {
- MOUNT_EXTERNAL_NONE = 0,
- MOUNT_EXTERNAL_DEFAULT = 1,
- MOUNT_EXTERNAL_READ = 2,
- MOUNT_EXTERNAL_WRITE = 3,
- MOUNT_EXTERNAL_LEGACY = 4,
- MOUNT_EXTERNAL_INSTALLER = 5,
- MOUNT_EXTERNAL_FULL = 6,
- MOUNT_EXTERNAL_PASS_THROUGH = 7,
- MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
- MOUNT_EXTERNAL_COUNT = 9
-};
-
-// The order of entries here must be kept in sync with MountExternalKind enum values.
-static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorageViews = {
- "", // MOUNT_EXTERNAL_NONE
- "/mnt/runtime/default", // MOUNT_EXTERNAL_DEFAULT
- "/mnt/runtime/read", // MOUNT_EXTERNAL_READ
- "/mnt/runtime/write", // MOUNT_EXTERNAL_WRITE
- "/mnt/runtime/write", // MOUNT_EXTERNAL_LEGACY
- "/mnt/runtime/write", // MOUNT_EXTERNAL_INSTALLER
- "/mnt/runtime/full", // MOUNT_EXTERNAL_FULL
- "/mnt/runtime/full", // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE)
- "/mnt/runtime/full", // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE)
+ MOUNT_EXTERNAL_NONE = 0,
+ MOUNT_EXTERNAL_DEFAULT = 1,
+ MOUNT_EXTERNAL_INSTALLER = 5,
+ MOUNT_EXTERNAL_PASS_THROUGH = 7,
+ MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
+ MOUNT_EXTERNAL_COUNT = 9
};
// Must match values in com.android.internal.os.Zygote.
diff --git a/core/proto/android/inputmethodservice/inputmethodservice.proto b/core/proto/android/inputmethodservice/inputmethodservice.proto
new file mode 100644
index 0000000..3b4ebb5
--- /dev/null
+++ b/core/proto/android/inputmethodservice/inputmethodservice.proto
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/inputmethodservice/softinputwindow.proto";
+import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+
+package android.inputmethodservice;
+
+option java_multiple_files = true;
+
+message InputMethodServiceProto {
+ optional SoftInputWindowProto soft_input_window = 1;
+ optional bool views_created= 2;
+ optional bool decor_view_visible = 3;
+ optional bool decor_view_was_visible = 4;
+ optional bool window_visible = 5;
+ optional bool in_show_window = 6;
+ optional string configuration = 7;
+ optional string token = 8;
+ optional string input_binding = 9;
+ optional bool input_started = 10;
+ optional bool input_view_started = 11;
+ optional bool candidates_view_started = 12;
+ optional .android.view.inputmethod.EditorInfoProto input_editor_info = 13;
+ optional bool show_input_requested = 14;
+ optional bool last_show_input_requested = 15;
+ optional bool can_pre_render = 16;
+ optional bool is_pre_rendered = 17;
+ optional int32 show_input_flags = 18;
+ optional int32 candidates_visibility = 19;
+ optional bool fullscreen_applied = 20;
+ optional bool is_fullscreen = 21;
+ optional bool extract_view_hidden = 22;
+ optional int32 extracted_token = 23;
+ optional bool is_input_view_shown = 24;
+ optional int32 status_icon = 25;
+ optional InsetsProto last_computed_insets = 26;
+ optional string settings_observer = 27;
+
+ message InsetsProto {
+ optional int32 content_top_insets = 1;
+ optional int32 visible_top_insets = 2;
+ optional int32 touchable_insets = 3;
+ optional string touchable_region = 4;
+ }
+}
\ No newline at end of file
diff --git a/core/proto/android/inputmethodservice/softinputwindow.proto b/core/proto/android/inputmethodservice/softinputwindow.proto
new file mode 100644
index 0000000..85b7d73
--- /dev/null
+++ b/core/proto/android/inputmethodservice/softinputwindow.proto
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+
+package android.inputmethodservice;
+
+option java_multiple_files = true;
+
+message SoftInputWindowProto {
+ optional string name = 1;
+ optional int32 window_type = 2;
+ optional int32 gravity = 3;
+ optional bool takes_focus = 4;
+ optional .android.graphics.RectProto bounds = 5;
+ optional int32 window_state = 6;
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 5091270..16a691c 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -463,6 +463,8 @@
// Updatable Driver - List of Apps selected to use updatable prerelease driver
// i.e. <pkg1>,<pkg2>,...,<pkgN>
optional SettingProto updatable_driver_prerelease_opt_in_apps = 18;
+
+ optional SettingProto angle_egl_features = 19;
}
optional Gpu gpu = 59;
diff --git a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
new file mode 100644
index 0000000..35aae8f
--- /dev/null
+++ b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+
+package android.server.inputmethod;
+
+option java_multiple_files = true;
+
+message InputMethodManagerServiceProto {
+ optional string cur_method_id = 1;
+ optional int32 cur_seq = 2;
+ optional string cur_client = 3;
+ optional string cur_focused_window_name = 4;
+ optional string last_ime_target_window_name = 5;
+ optional string cur_focused_window_soft_input_mode = 6;
+ optional .android.view.inputmethod.EditorInfoProto cur_attribute = 7;
+ optional string cur_id = 8;
+ optional bool show_requested = 9;
+ optional bool show_explicitly_requested = 10;
+ optional bool show_forced = 11;
+ optional bool input_shown = 12;
+ optional bool in_fullscreen_mode = 13;
+ optional string cur_token = 14;
+ optional int32 cur_token_display_id = 15;
+ optional bool system_ready = 16;
+ optional int32 last_switch_user_id = 17;
+ optional bool have_connection = 18;
+ optional bool bound_to_method = 19;
+ optional bool is_interactive = 20;
+ optional int32 back_disposition = 21;
+ optional int32 ime_window_visibility = 22;
+ optional bool show_ime_with_hard_keyboard = 23;
+ optional bool accessibility_requesting_no_soft_keyboard = 24;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index d4b226d..d315ff2 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -30,6 +30,10 @@
import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/typedef.proto";
+import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
+import "frameworks/base/core/proto/android/view/insetssource.proto";
+import "frameworks/base/core/proto/android/view/insetssourcecontrol.proto";
+
package com.android.server.wm;
option java_multiple_files = true;
@@ -47,6 +51,7 @@
optional int32 rotation = 7 [(.android.typedef) = "android.view.Surface.Rotation"];
optional int32 last_orientation = 8 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
optional int32 focused_display_id = 9;
+ optional bool hard_keyboard_available = 10;
}
/* represents RootWindowContainer object */
@@ -195,6 +200,13 @@
optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
repeated TaskProto tasks = 25 [deprecated=true];
optional bool display_ready = 26;
+
+ optional WindowStateProto input_method_target = 27;
+ optional WindowStateProto input_method_input_target = 28;
+ optional WindowStateProto input_method_control_target = 29;
+ optional WindowStateProto current_focus = 30;
+ optional ImeInsetsSourceProviderProto ime_insets_source_provider = 31;
+ optional bool can_show_ime = 32;
}
/* represents DisplayArea object */
@@ -226,6 +238,8 @@
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional .android.graphics.RectProto stable_bounds = 1;
+ optional .android.graphics.RectProto dock = 2;
+ optional .android.graphics.RectProto current = 3;
}
/* represents DockedStackDividerController */
@@ -488,3 +502,31 @@
optional .android.graphics.RectProto stable_insets = 14;
optional .android.graphics.RectProto outsets = 15;
}
+
+message InsetsSourceProviderProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional .android.view.InsetsSourceProto source = 1;
+ optional .android.graphics.RectProto frame = 2;
+ optional .android.view.InsetsSourceControlProto fake_control = 3;
+ optional .android.view.InsetsSourceControlProto control = 4;
+ optional WindowStateProto control_target = 5;
+ optional WindowStateProto pending_control_target = 6;
+ optional WindowStateProto fake_control_target = 7;
+ optional .android.view.SurfaceControlProto captured_leash = 8;
+ optional .android.graphics.RectProto ime_overridden_frame = 9;
+ optional bool is_leash_ready_for_dispatching = 10;
+ optional bool client_visible = 11;
+ optional bool server_visible = 12;
+ optional bool seamless_rotating = 13;
+ optional int64 finish_seamless_rotate_frame_number = 14;
+ optional bool controllable = 15;
+}
+
+message ImeInsetsSourceProviderProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional InsetsSourceProviderProto insets_source_provider = 1;
+ optional WindowStateProto ime_target_from_ime = 2;
+ optional bool is_ime_layout_drawn = 3;
+}
\ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index f31d35b..856d8da 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -26,6 +26,9 @@
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
+import "frameworks/base/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto";
+import "frameworks/base/core/proto/android/inputmethodservice/inputmethodservice.proto";
+
/**
* Represents a file full of input method editor trace entries.
* Encoded, it should start with 0x9 0x49 0x4d 0x45 0x54 0x52 0x41 0x43 0x45 (.IMETRACE), such
@@ -54,6 +57,8 @@
/* required: elapsed realtime in nanos since boot of when this entry was logged */
optional fixed64 elapsed_realtime_nanos = 1;
optional ClientsProto clients = 2;
+ optional .android.inputmethodservice.InputMethodServiceProto input_method_service = 3;
+ optional .android.server.inputmethod.InputMethodManagerServiceProto input_method_manager_service = 4;
// this wrapper helps to simplify the dumping logic
message ClientsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 846ed87..c8b8ef2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1247,8 +1247,19 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_recordAudio"
android:description="@string/permdesc_recordAudio"
+ android:backgroundPermission="android.permission.RECORD_BACKGROUND_AUDIO"
android:protectionLevel="dangerous|instant" />
+ <!-- Allows an application to record audio while in the background.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.RECORD_BACKGROUND_AUDIO"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_recordBackgroundAudio"
+ android:description="@string/permdesc_recordBackgroundAudio"
+ android:permissionFlags="hardRestricted|installerExemptIgnored"
+ android:protectionLevel="dangerous" />
+
<!-- ====================================================================== -->
<!-- Permissions for activity recognition -->
<!-- ====================================================================== -->
@@ -1316,8 +1327,19 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_camera"
android:description="@string/permdesc_camera"
+ android:backgroundPermission="android.permission.BACKGROUND_CAMERA"
android:protectionLevel="dangerous|instant" />
+ <!-- Required to be able to access the camera device in the background.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.BACKGROUND_CAMERA"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_backgroundCamera"
+ android:description="@string/permdesc_backgroundCamera"
+ android:permissionFlags="hardRestricted|installerExemptIgnored"
+ android:protectionLevel="dangerous" />
+
<!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
system only camera devices.
<p>Protection level: system|signature
@@ -1556,6 +1578,13 @@
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to install a LocationTimeZoneProvider into the
+ LocationTimeZoneProviderManager.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
This should only be used by HDMI-CEC service.
-->
@@ -2690,6 +2719,14 @@
<permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"
android:protectionLevel="signature" />
+ <!-- Allows applications like settings to manage configuration associated with automatic time
+ and time zone detection.
+ <p>Not for use by third-party applications.
+ @SystemApi @hide
+ -->
+ <permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION"
+ android:protectionLevel="signature|privileged" />
+
<!-- ==================================================== -->
<!-- Permissions related to changing status bar -->
<!-- ==================================================== -->
@@ -3549,6 +3586,13 @@
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
+ <!-- This permission is required by Media Resource Observer Service when
+ accessing its registerObserver Api.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER"
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 58d6a86..e6b7c68 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"verander jou klankinstellings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Laat die program toe om globale klankinstellings soos volume en watter luidspreker vir uitvoer gebruik word, te verander."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"neem klank op"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Hierdie program kan enige tyd oudio met die mikrofoon opneem."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"stuur bevele na die SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Laat die program toe om bevele na die SIM te stuur. Dit is baie gevaarlik."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"herken fisieke aktiwiteit"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Hierdie program kan jou fisieke aktiwiteit herken."</string>
<string name="permlab_camera" msgid="6320282492904119413">"neem foto\'s en video\'s"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Hierdie program kan enige tyd met die kamera foto\'s neem en video\'s opneem."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Gee \'n program of diens toegang tot stelselkameras om foto\'s en video\'s te neem"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Hierdie bevoorregte of stelselprogram kan enige tyd met \'n stelselkamera foto\'s neem en video\'s opneem. Vereis dat die program ook die android.permission.CAMERA-toestemming het"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Laat \'n program of diens toe om terugbeloproepe te ontvang oor kameratoestelle wat oopgemaak of toegemaak word."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Skakel kortpad vir toeganklikheidskenmerke aan?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit toeganklikheidkenmerke aan. Dit kan verander hoe jou toestel werk.\n\nHuidige kenmerke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJy kan geselekteerde kenmerke in Instellings en Toeganklikheid verander."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Skakel <xliff:g id="SERVICE">%1$s</xliff:g>-kortpad aan?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit <xliff:g id="SERVICE">%1$s</xliff:g>, \'n toeganklikheidkenmerk, aan. Dit kan verander hoe jou toestel werk.\n\nJy kan hierdie kortpad na \'n ander kenmerk in Instellings en Toeganklikheid verander."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Skakel aan"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Moenie aanskakel nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b3878d8..9750a0c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ይህ መተግበሪያ በማናቸውም ጊዜ ማይክራፎኑን በመጠቀም ኦዲዮን መቅዳት ይችላል።"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ወደ ሲሙ ትዕዛዞችን መላክ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"መተግበሪያው ትዕዛዞችን ወደ ሲሙ እንዲልክ ያስችለዋል። ይሄ በጣማ አደገኛ ነው።"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"አካላዊ እንቅስቃሴን ለይቶ ማወቅ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ይህ መተግበሪያ አካላዊ እንቅስቃሴዎን ለይቶ ሊያውቅ ይችላል።"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ፎቶዎች እና ቪዲዮዎች ያንሱ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ይህ መተግበሪያ በማናቸውም ጊዜ ካሜራውን በመጠቀም ፎቶ ሊያነሳ እና ቪዲዮዎችን ሊቀርጽ ይችላል።"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ሥዕሎችን ለማንሣት እና ቪዲዮዎችን ለመቅረጽ እንዲችሉ ወደ ሥርዓት ካሜራዎች ለመተግበሪያ ወይም ለአገልግሎት መዳረሻ ይፍቀዱ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ይህ ልዩ ፈቃድ ያለው የሥርዓት መተግበሪያ በማንኛውም ጊዜ የሥርዓት ካሜራን በመጠቀም ሥዕሎችን ማንሣት እና ቪዲዮ መቅረጽ ይችላል። የandroid.permission.CAMERA ፈቃዱ በመተግበሪያውም ጭምር እንዲያዝ ያስፈልገዋል።"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"አንድ መተግበሪያ ወይም አገልግሎት እየተከፈቱ ወይም እየተዘጉ ስላሉ የካሜራ መሣሪያዎች መልሶ ጥሪዎችን እንዲቀበል ይፍቀዱ።"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"የተደራሽነት አቋራጭ ጥቅም ላይ ይዋል?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"አቋራጩ ሲበራ ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"የተደራሽነት ባህሪዎች አቋራጭ ይብራ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nየአሁን ባሕሪያት፦\n<xliff:g id="SERVICE">%1$s</xliff:g>\nበቅንብሮች > ተደራሽነት ውስጥ የተመረጡትን ባሕሪያት መለወጥ ይችላሉ።"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"የ<xliff:g id="SERVICE">%1$s</xliff:g> አቋራጭ ይብራ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን <xliff:g id="SERVICE">%1$s</xliff:g> ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nበቅንብሮች > ተደራሽነት ውስጥ ወደ ሌላ ባሕሪ ይህን አቋራጭ መለወጥ ይችላሉ።"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"አብራ"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"አታብራ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 44055e1..e672de3 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -444,13 +444,23 @@
<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="3976213377904701093">"يمكن لهذا التطبيق تسجيل الصوت باستخدام الميكروفون في أي وقت."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"إرسال أوامر إلى شريحة SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"السماح للتطبيق بإرسال أوامر إلى شريحة SIM. وهذا أمر بالغ الخطورة."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"التعرّف على النشاط البدني"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"يمكن لهذا التطبيق التعرّف على نشاطك البدني."</string>
<string name="permlab_camera" msgid="6320282492904119413">"التقاط صور وفيديوهات"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"يمكن لهذا التطبيق التقاط صور وتسجيل فيديوهات باستخدام الكاميرا في أي وقت."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"السماح لتطبيق أو خدمة بالوصول إلى كاميرات النظام لالتقاط صور وتسجيل فيديوهات"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"إنّ تطبيق النظام هذا، أو التطبيق المزوّد بأذونات مميّزة، يمكنه التقاط صور وتسجيل فيديوهات باستخدام كاميرا النظام في أي وقت. ويجب أن يحصل التطبيق أيضًا على الإذن android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"يسمح الإذن لتطبيق أو خدمة بتلقّي استدعاءات عما إذا كانت أجهزة الكاميرات مفتوحة أو مغلقة."</string>
@@ -1710,12 +1720,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"هل تريد استخدام اختصار \"سهولة الاستخدام\"؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"عند تفعيل الاختصار، يؤدي الضغط على زرّي التحكّم في مستوى الصوت معًا لمدة 3 ثوانٍ إلى تفعيل إحدى ميزات إمكانية الوصول."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"هل تريد تفعيل الاختصار لميزات إمكانية الوصول؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"يؤدي الضغط مع الاستمرار على كلا مفتاحَي التحكّم في مستوى الصوت لبضع ثوانٍ إلى تفعيل ميزات إمكانية الوصول. قد يؤدي هذا الإجراء إلى تغيير طريقة عمل جهازك.\n\nالميزات الحالية:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nيمكنك تغيير الميزات المحددة في الإعدادات > إمكانية الوصول."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"هل تريد تفعيل اختصار <xliff:g id="SERVICE">%1$s</xliff:g>؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"يؤدي الضغط مع الاستمرار لبضع ثوانٍ على كلا مفتاحَي التحكّم في مستوى الصوت إلى تفعيل <xliff:g id="SERVICE">%1$s</xliff:g> وهي إحدى ميزات إمكانية الوصول. يمكن أن يؤدي هذا الإجراء إلى تغيير كيفية عمل جهازك.\n\nيمكنك تغيير هذا الاختصار لاستخدامه مع ميزة أخرى في الإعدادات > أدوات تمكين الوصول."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"تفعيل"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"عدم التفعيل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e787f23..b3e1680 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"এই এপটোৱে যিকোনো সময়তে মাইক্ৰ\'ফ\'ন ব্যৱহাৰ কৰি অডিঅ\' ৰেকৰ্ড কৰিব পাৰে।"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ছিমলৈ নিৰ্দেশ পঠিয়াব পাৰে"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ছিমলৈ নিৰ্দেশসমূহ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ই অতি ক্ষতিকাৰক।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰক"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"এই এপটোৱে আপোনাৰ শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰিব পাৰে।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ফট\' তোলা আৰু ভিডিঅ\' ৰেকৰ্ড কৰা"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"এই এপে যিকোনো সময়তে কেমেৰা ব্যৱহাৰ কৰি ফট\' তুলিব আৰু ভিডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ফট’ উঠাবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ এটা এপ্লিকেশ্বন অথবা সেৱাক ছিষ্টেম কেমেৰাসমূহ এক্সেছ কৰিবলৈ দিয়ক"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই বিশেষাধিকাৰ প্ৰাপ্ত অথবা ছিষ্টেম এপ্টোৱে এটা ছিষ্টেম কেমেৰা ব্যৱহাৰ কৰি যিকোনো সময়তে ফট’ উঠাব পাৰে আৰু ভিডিঅ’ ৰেকৰ্ড কৰিব পাৰে। লগতে এপ্টোৰো android.permission.CAMERAৰ অনুমতি থকাটো প্ৰয়োজনীয়"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনো এপ্লিকেশ্বন অথবা সেৱাক কেমেৰা ডিভাইচসমূহ খোলা অথবা বন্ধ কৰাৰ বিষয়ে কলবেকসমূহ গ্ৰহণ কৰিবলৈ অনুমতি দিয়ক।"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"সাধ্য সুবিধাসমূহৰ বাবে শ্বৰ্টকাট অন কৰিবনে?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে সাধ্য-সুবিধাসমূহ অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nবর্তমানৰ সুবিধাসমূহ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nআপুনি ছেটিংসমূহ > সাধ্য-সুবিধাত কিছুমান নিৰ্দিষ্ট সুবিধা সলনি কৰিব পাৰে।"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>ৰ শ্বৰ্টকাট অন কৰিবনে?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে এটা সাধ্য- সুবিধা <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nআপুনি ছেটিংসমূহ > সাধ্য-সুবিধাসমূহত এই শ্বৰ্টকাটটো অন্য এটা সুবিধালৈ সলনি কৰিব পাৰে।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"অন কৰক"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"অন নকৰিব"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index af57cf9..de399df 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"audio ayarlarınızı dəyişir"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tətbiqə səs və hansı spikerin çıxış üçün istifadə olunduğu kimi qlobal səs ayarlarını dəyişdirməyə imkan verir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"səs yaz"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Bu tətbiq istədiyiniz zaman mikrofonu istifadə edərək audio qeyd edə bilər."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"əmrləri SIM\'ə göndərin"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tətbiqə SIM-ə əmrlər göndərməyə imkan verir. Bu, çox təhlükəlidir."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziki fəaliyyəti tanıyın"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu tətbiq fiziki fəaliyyətinizi tanıya bilər."</string>
<string name="permlab_camera" msgid="6320282492904119413">"şəkil və video çəkmək"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Bu tətbiq istədiyiniz zaman kameranı istifadə edərək şəkil çəkə və video qeydə ala bilər."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Şəkil və video çəkmək üçün tətbiq və ya xidmətlərin sistem kameralarına girişinə icazə verin"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu icazəli və ya sistem tətbiqi istənilən vaxt sistem kamerasından istifadə edərək şəkil və videolar çəkə bilər. android.permission.CAMERA icazəsinin də tətbiq tərəfindən saxlanılmasını tələb edir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tətbiqə və ya xidmətə kamera cihazlarının açılması və ya bağlanması haqqında geri zənglər qəbul etməyə icazə verin."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Əlçatımlılıq funksiyaları üçün qısayol aktiv edilsin?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyaları aktiv olur. Bu, cihazınızın işləmə qaydasını dəyişə bilər.\n\nCari funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAyarlar və Əlçatımlılıq bölməsində seçilmiş funksiyaları dəyişə bilərsiniz."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> qısayolu aktiv edilsin?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyası olan <xliff:g id="SERVICE">%1$s</xliff:g> aktiv olur. Bu, cihazınızın işləmə qaydasını dəyişə bilər.\n\nAyarlar və Əlçatımlılıq bölməsində bu qısayolu başqa bir funksiyata dəyişə bilərsiniz."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktiv edin"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Aktiv etməyin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 465e9d2..928ade1 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -435,13 +435,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"promena audio podešavanja"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Dozvoljava aplikaciji da menja globalna audio podešavanja kao što su jačina zvuka i izbor zvučnika koji se koristi kao izlaz."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje audio zapisa"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ova aplikacija može da snima zvuk pomoću mikrofona u bilo kom trenutku."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi na SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji da šalje komande SIM kartici. To je veoma opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičkih aktivnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može da prepozna fizičke aktivnosti."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimanje fotografija i video snimaka"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ova aplikacija može da snima fotografije i video snimke pomoću kamere u bilo kom trenutku."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dozvolite nekoj aplikaciji ili usluzi da pristupa kamerama sistema da bi snimala slike i video snimke"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova privilegovana sistemska aplikacija može da snima slike i video snimke pomoću kamere sistema u bilo kom trenutku. Aplikacija treba da ima i dozvolu android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvolite aplikaciji ili usluzi da dobija povratne pozive o otvaranju ili zatvaranju uređaja sa kamerom."</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite da uključite prečicu za funkcije pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključiće se funkcije pristupačnosti. To može da promeni način rada uređaja.\n\nPostojeće funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nMožete da promenite izabrane funkcije u odeljku Podešavanja > Pristupačnost."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite da uključite prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključuje se <xliff:g id="SERVICE">%1$s</xliff:g>, funkcija pristupačnosti. To može da promeni način rada uređaja.\n\nMožete da promenite funkciju na koju se odnosi ova prečica u odeljku Podešavanja > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ne uključuj"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index f0594a1..e31c4b7 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -438,13 +438,23 @@
<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="3976213377904701093">"Гэта праграма можа у любы час запісваць аўдыя, выкарыстоўваючы мікрафон."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"адпраўляць каманды на SIM-карту"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"распазнаваць фізічную актыўнасць"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Гэта праграма можа распазнаваць фізічную актыўнасць."</string>
<string name="permlab_camera" msgid="6320282492904119413">"рабіць фатаграфіі і відэа"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Гэта праграма можа рабіць фота і запісваць відэа з дапамогай камеры ў любы час."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дазволіць праграме або сэрвісу атрымліваць доступ да сістэмных камер, каб здымаць фота і запісваць відэа"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Гэта прыярытэтная ці сістэмная праграма можа здымаць фота і запісваць відэа з дапамогай сістэмнай камеры. Праграме таксама патрэбны дазвол android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дазволіць праграме ці сэрвісу атрымліваць зваротныя выклікі наконт адкрыцця ці закрыцця прылад камеры."</string>
@@ -970,7 +980,7 @@
<string name="permlab_addVoicemail" msgid="4770245808840814471">"дадаць галасавое паведамленне"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"Дазваляе прыкладанням дадаваць паведамленні ў вашу скрыню галасавой пошты."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"змяніць дазволы геапазіцыянавання для браўзэра"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Дазваляе праграме змяняць дазволы геалакацыі браўзера. Шкодныя праграмы могуць выкарыстоўваць гэта, каб адпраўляць даныя аб месцазнаходжанні на любыя вэб-сайты."</string>
<string name="save_password_message" msgid="2146409467245462965">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"Не зараз"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Запомніць"</string>
@@ -1345,8 +1355,8 @@
<string name="usb_tether_notification_title" msgid="8828527870612663771">"Рэжым USB-мадэма"</string>
<string name="usb_midi_notification_title" msgid="7404506788950595557">"MIDI праз USB"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"USB-прылада падключана"</string>
- <string name="usb_notification_message" msgid="4715163067192110676">"Дакраніцеся, каб атрымаць іншыя параметры."</string>
- <string name="usb_power_notification_message" msgid="7284765627437897702">"Зарадка падключанай прылады. Націсніце, каб убачыць іншыя параметры."</string>
+ <string name="usb_notification_message" msgid="4715163067192110676">"Дакраніцеся, каб убачыць іншыя параметры."</string>
+ <string name="usb_power_notification_message" msgid="7284765627437897702">"Падключаная прылада зараджаецца. Дакраніцеся, каб убачыць іншыя параметры."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Выяўлены аксесуар аналагавага аўдыя"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Далучаная прылада не сумяшчальная з гэтым тэлефонам. Націсніце, каб даведацца больш."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Адладка па USB падключана"</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Калі хуткі доступ уключаны, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб запусціць функцыю спецыяльных магчымасцей."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Уключыць хуткі доступ да спецыяльных магчымасцей?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае спецыяльныя магчымасці. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nБягучыя функцыі:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВыбраныя функцыі можна змяніць у меню \"Налады > Спецыяльныя магчымасці\"."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Уключыць хуткі доступ да сэрвісу \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае службу \"<xliff:g id="SERVICE">%1$s</xliff:g>\", якая з\'яўляецца спецыяльнай магчымасцю. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nВы можаце задаць гэта спалучэнне клавіш для іншай функцыі ў меню \"Налады > Спецыяльныя магчымасці\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Уключыць"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Не ўключаць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 99f6072..5938fd9 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Това приложение може по всяко време да записва звук посредством микрофона."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"изпращане на команди до SIM картата"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Разрешава на приложението да изпраща команди до SIM картата. Това е много опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"разпознаване на физическата активност"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Това приложение може да разпознава физическата ви активност."</string>
<string name="permlab_camera" msgid="6320282492904119413">"правене на снимки и видеоклипове"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Това приложение може по всяко време да прави снимки и да записва видео посредством камерата."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Разрешаване на достъп на приложение или услуга до системните камери с цел правене на снимки и видеоклипове"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Това привилегировано или системно приложение може по всяко време да прави снимки и да записва видео посредством системна камера. Необходимо е също на приложението да бъде дадено разрешението android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешаване на приложение или услуга да получават обратни повиквания за отварянето или затварянето на снимачни устройства."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Искате ли да използвате пряк път към функцията за достъпност?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за силата на звука и ги задържите за 3 секунди."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Искате ли да включите прекия път за функциите за достъпност?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функциите за достъпност. Това може да промени начина, по който работи устройството ви.\n\nТекущи функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените избраните функции от „Настройки“ > „Достъпност“."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Искате ли да включите прекия път за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функцията за достъпност <xliff:g id="SERVICE">%1$s</xliff:g>. Това може да промени начина, по който работи устройството ви.\n\nМожете да зададете друга функция за този пряк път от „Настройки“ > „Достъпност“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включване"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Без включване"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index a07a1fe..3567d79 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যে কোনো সময় অডিও রেকর্ড করতে পারে৷"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"সিম এ আদেশগুলি পাঠান"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"অ্যাপ্লিকেশানটিকে সিম কার্ডে কমান্ডগুলি পাঠানোর অনুমতি দেয়৷ এটি খুবই বিপজ্জনক৷"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"শারীরিক অ্যাক্টিভিটি শনাক্ত করুন"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"এই অ্যাপ আপনার শারীরিক অ্যাক্টিভিটি শনাক্ত করতে পারবে।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ছবি এবং ভিডিও তোলে"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"এই অ্যাপটি যে কোনো সময় ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারে৷"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"সিস্টেম ক্যামেরা ব্যবহার করে ফটো এবং ভিডিও নেওয়ার জন্য অ্যাপ্লিকেশন বা পরিষেবা অ্যাক্সেসের অনুমতি দিন"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই প্রিভিলেজ বা সিস্টেম অ্যাপ যেকোনও সময় সিস্টেম ক্যামেরা ব্যবহার করে ছবি তুলতে ও ভিডিও রেকর্ড করতে পারে। এই অ্যাপকে android.permission.CAMERA অনুমতি দিতে হবে"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনও অ্যাপ্লিকেশন বা পরিষেবাকে ক্যামেরা ডিভাইসগুলি খোলা বা বন্ধ হওয়া সম্পর্কে কলব্যাকগুলি গ্রহণ করার অনুমতি দিন।"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"অ্যাক্সেসযোগ্যতা শর্টকাট ব্যবহার করবেন?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শর্টকাট চালু করা থাকাকালীন দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি ফিচার চালু হবে।"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"অ্যাক্সেসিবিলিটি ফিচারের শর্টকাট বন্ধ করতে চান?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে অ্যাক্সেসিবিলিটি ফিচার চালু হয়ে যাবে। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nবর্তমান ফিচার:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nসেটিংস > অ্যাক্সেসিবিলিটি বিকল্প থেকে আপনি বাছাই করা ফিচার পরিবর্তন করতে পারবেন।"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> শর্টকাট চালু করতে চান?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে <xliff:g id="SERVICE">%1$s</xliff:g> চালু হয়ে যাবে। এটি একটি অ্যাক্সেসিবিলিটি ফিচার। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nসেটিংস > অ্যাক্সেসিবিলিটি থেকে আপনি এই শর্টকাট পরিবর্তন করতে পারবেন।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"চালু করুন"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"চালু করবেন না"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 1292fc1..2c05aa5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -435,13 +435,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"izmjene postavki zvuka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Omogućava aplikaciji izmjenu općih postavki zvuka, kao što su jačina zvuka i izbor izlaznog zvučnika."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje audiozapisa"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ova aplikacija može u svakom trenutku snimati zvuk koristeći mikrofon."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi SIM kartici"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji slanje naredbi na SIM. Ovo je vrlo opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičke aktivnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može prepoznati vašu fizičku aktivnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimanje slika i videozapisa"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ova aplikacija može slikati fotografije i snimati videozapise koristeći kameru bilo kada."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dopustite aplikaciji ili usluzi da pristupa kamerama sistema radi snimanja fotografija i videozapisa"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena ili sistemska aplikacija u svakom trenutku može snimati fotografije i videozapise pomoću kamere sistema. Aplikacija također mora imati odobrenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvoliti aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju kamera."</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Uključiti prečicu za funkcije pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkcije pristupačnosti. Ovo može uticati na način rada uređaja.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane funkcije možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Uključiti prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkciju pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Ovo može promijeniti način rada uređaja.\n\nOvu prečicu možete zamijeniti drugom funkcijom u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nemoj uključiti"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 28d961b..0a25ba0 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"canviar la configuració d\'àudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet que l\'aplicació modifiqui la configuració d\'àudio general, com ara el volum i l\'altaveu de sortida que es fa servir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar àudio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Aquesta aplicació pot gravar àudio amb el micròfon en qualsevol moment."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar ordres a la SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet que l\'aplicació enviï ordres a la SIM. Això és molt perillós."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconèixer l\'activitat física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aquesta aplicació pot reconèixer la teva activitat física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fer fotos i vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Aquesta aplicació pot fer fotos i gravar vídeos amb la càmera en qualsevol moment."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permet que una aplicació o un servei tinguin accés a les càmeres del sistema per fer fotos i vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aquesta aplicació del sistema amb privilegis pot fer fotos i gravar vídeos amb una càmera del sistema en qualsevol moment. L\'aplicació també ha de tenir el permís android.permission.CAMERA per accedir-hi."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permet que una aplicació o un servei pugui rebre crides de retorn sobre els dispositius de càmera que s\'obren o es tanquen."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si la drecera està activada, prem els dos botons de volum durant 3 segons per iniciar una funció d\'accessibilitat."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vols desactivar la drecera de les funcions d\'accessibilitat?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantens premudes les dues tecles de volum durant uns segons, s\'activaran les funcions d\'accessibilitat. Això podria canviar el funcionament del teu dispositiu.\n\nFuncions actuals:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPots canviar les funcions seleccionades a Configuració > Accessibilitat."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vols activar la drecera de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantens premudes les dues tecles de volum durant uns segons, la funció d\'accessibilitat <xliff:g id="SERVICE">%1$s</xliff:g> s\'activarà. Això podria canviar el funcionament del teu dispositiu.\n\nPots canviar la funció d\'aquesta drecera a Configuració > Accessibilitat."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activa"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"No activis"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 89f679e..8321f22 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -438,13 +438,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"změna nastavení zvuku"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Umožňuje aplikaci změnit globální nastavení zvuku, například hlasitost či reproduktor pro výstup zvuku."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nahrávání zvuku"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Tato aplikace může pomocí mikrofonu kdykoli zaznamenat zvuk."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"odesílání příkazů do SIM karty"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikaci odesílat příkazy na kartu SIM. Toto oprávnění je velmi nebezpečné."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávání fyzické aktivity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Tyto aplikace dokážou rozpoznat vaši fyzickou aktivitu."</string>
<string name="permlab_camera" msgid="6320282492904119413">"pořizování fotografií a videí"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Tato aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Povolte aplikaci nebo službě k systémovým fotoaparátům za účelem pořizování fotek a videí"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tato privilegovaná nebo systémová aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video. Aplikace musí zároveň mít oprávnění android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povolte aplikaci nebo službě přijímat zpětná volání o otevření nebo zavření zařízení s fotoaparátem."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Zapnout zkratku funkcí pro usnadnění přístupu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkce pro usnadnění přístupu. Tato funkce může změnit fungování zařízení.\n\nAktuální funkce:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkce můžete změnit v Nastavení > Přístupnost."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Zapnout zkratku služby <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkci pro usnadnění přístupu <xliff:g id="SERVICE">%1$s</xliff:g>. Tato funkce může změnit fungování zařízení.\n\nZkratku můžete nastavit na jinou funkci v Nastavení > Přístupnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnout"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nezapínat"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e9d477d..d85db8f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"skifte dine lydindstillinger"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tillader, at appen kan ændre globale lydindstillinger, som f.eks. lydstyrke og hvilken højttaler der bruges til output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"optage lyd"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Denne app kan til enhver tid optage lyd via mikrofonen."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"send kommandoer til SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillader, at appen sender kommandoer til SIM-kortet. Dette er meget farligt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"genkend fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Denne app kan genkende din fysiske aktivitet."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tage billeder og optage video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Med denne app kan du tage billeder og optage video med kameraet når som helst."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Giv en app eller tjeneste adgang til systemkameraer for at tage billeder og optage video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerede app eller systemapp kan til enhver tid tage billeder og optage video med et systemkamera. Appen skal også have tilladelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillad, at en app eller tjeneste modtager tilbagekald om kameraenheder, der åbnes eller lukkes."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når genvejen er aktiveret, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du aktivere genvejen til hjælpefunktioner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionerne. Det kan ændre på, hvordan din enhed fungerer.\n\nAktuelle funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ændre de valgte funktioner i Indstillinger > Hjælpefunktioner."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du aktivere <xliff:g id="SERVICE">%1$s</xliff:g>-genvejen?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionen <xliff:g id="SERVICE">%1$s</xliff:g>. Det kan ændre på, hvordan din enhed fungerer.\n\nDu kan ændre denne genvej til en anden funktion i Indstillinger > Hjælpefunktioner."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivér"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Aktivér ikke"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 682491e..e4fabbc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"Audio-Einstellungen ändern"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ermöglicht der App, globale Audio-Einstellungen zu ändern, etwa die Lautstärke und den Lautsprecher für die Ausgabe."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Diese App kann jederzeit Audio über das Mikrofon aufnehmen."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"Befehle an die SIM senden"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"Körperliche Aktivitäten erkennen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Diese App kann deine körperliche Aktivität erkennen."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Bilder und Videos aufnehmen"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Diese App kann mit der Kamera jederzeit Bilder und Videos aufnehmen."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Einer App oder einem Dienst Zugriff auf Systemkameras erlauben, um Fotos und Videos aufnehmen zu können"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Diese privilegierte App oder System-App kann jederzeit mit einer Systemkamera Bilder und Videos aufnehmen. Die App benötigt auch die Berechtigung \"android.permission.CAMERA\"."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Einer App oder einem Dienst den Empfang von Callbacks erlauben, wenn eine Kamera geöffnet oder geschlossen wird."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Verknüpfung für Bedienungshilfen aktivieren?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfen. Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nAktuelle Funktionen:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kannst ausgewählte Funktionen unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Verknüpfung für <xliff:g id="SERVICE">%1$s</xliff:g> aktivieren?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfe \"<xliff:g id="SERVICE">%1$s</xliff:g>\". Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nUnter \"Einstellungen > \"Bedienungshilfen\" kannst du dieser Verknüpfung eine andere Funktion zuweisen."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivieren"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nicht aktivieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9449ca0..d9badc6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Αυτή η εφαρμογή μπορεί να κάνει εγγραφή ήχου χρησιμοποιώντας το μικρόφωνο, ανά πάσα στιγμή."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"στέλνει εντολές στην κάρτα SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Επιτρέπει στην εφαρμογή την αποστολή εντολών στην κάρτα SIM. Αυτό είναι εξαιρετικά επικίνδυνο."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"αναγνώριση σωματικής δραστηριότητας"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Αυτή η εφαρμογή μπορεί να αναγνωρίσει τη σωματική σας δραστηριότητα."</string>
<string name="permlab_camera" msgid="6320282492904119413">"κάνει λήψη φωτογραφιών και βίντεο"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Αυτή η εφαρμογή μπορεί να τραβήξει φωτογραφίες και βίντεο χρησιμοποιώντας την κάμερα, ανά πάσα στιγμή."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Παραχωρήστε σε μια εφαρμογή ή υπηρεσία πρόσβαση στις κάμερες του συστήματος για τη λήψη φωτογραφιών και βίντεο"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Αυτή η προνομιακή εφαρμογή ή εφαρμογή συστήματος μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο, χρησιμοποιώντας μια κάμερα του συστήματος ανά πάσα στιγμή. Απαιτείται, επίσης, η εφαρμογή να έχει την άδεια android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Επιτρέψτε σε μια εφαρμογή ή μια υπηρεσία να λαμβάνει επανάκλησεις σχετικά με το άνοιγμα ή το κλείσιμο συσκευών κάμερας."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Να χρησιμοποιείται η συντόμευση προσβασιμότητας;"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ενεργοποίηση συντόμευσης για λειτουργίες προσβασιμότητας;"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Για να ενεργοποιήσετε τις λειτουργίες προσβασιμότητας, πατήστε παρατεταμένα τα δύο πλήκτρα έντασης για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΤρέχουσες λειτουργίες:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nΜπορείτε να αλλάξετε τις επιλεγμένες λειτουργίες στις Ρυθμίσεις > Προσβασιμότητα."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ενεργοποίηση συντόμευσης <xliff:g id="SERVICE">%1$s</xliff:g>;"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Μπορείτε να ενεργοποιήσετε τη λειτουργία <xliff:g id="SERVICE">%1$s</xliff:g>, η οποία είναι μία από τις λειτουργίες προσβασιμότητας, πατώντας παρατεταμένα ταυτόχρονα τα δύο πλήκτρα έντασης ήχου για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΜπορείτε να αλλάξετε αυτή τη συντόμευση σε μια άλλη λειτουργία στις Ρυθμίσεις > Προσβασιμότητα."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ενεργοποίηση"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Να μην ενεργοποιηθούν"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0788a60..fac2f22 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
<string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 6e841ec..8497658 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
<string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
@@ -1123,8 +1127,8 @@
<string name="loading" msgid="3138021523725055037">"Loading…"</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <string name="checked" msgid="9179896827054513119">"ticked"</string>
- <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
+ <string name="checked" msgid="9179896827054513119">"checked"</string>
+ <string name="not_checked" msgid="7972320087569023342">"not checked"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
@@ -2025,7 +2029,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> spreadsheet"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"Presentation"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> presentation"</string>
- <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth will stay on during aeroplane mode"</string>
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth will stay on in Airplane mode"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Loading"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> files</item>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 731f184..12881e7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
<string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 8bd3597..cb2eb7a 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
<string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index f9793d2..5750e50 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recognize physical activity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognize your physical activity."</string>
<string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Allow an application or service access to system cameras to take pictures and videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0353000..f933a2f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar tu configuración de audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que la aplicación modifique la configuración de audio global, por ejemplo, el volumen y el altavoz de salida."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabar audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta app puede grabar audio con el micrófono en cualquier momento."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Usar este permiso es peligroso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta app puede reconocer tu actividad física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tomar fotografías y grabar videos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Esta app puede tomar fotos y grabar videos con la cámara en cualquier momento."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que una aplicación o un servicio accedan a las cámaras del sistema para tomar fotos y grabar videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app del sistema o con privilegios puede tomar fotografías y grabar videos con una cámara del sistema en cualquier momento. Para ello, requiere tener el permiso android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permite que una aplicación o un servicio reciba devoluciones de llamada cuando se abren o cierran dispositivos de cámara."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cuando la combinación de teclas está activada, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar la combinación de teclas para las funciones de accesibilidad?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantienes presionadas las dos teclas de volumen durante unos segundos, se activarán las funciones de accesibilidad. Esto puede cambiar el funcionamiento de tu dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Configuración > Accesibilidad."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantienes presionadas ambas teclas de volumen durante unos segundos, se activará la función de accesibilidad <xliff:g id="SERVICE">%1$s</xliff:g>. Esto podría cambiar la forma en que funciona tu dispositivo.\n\nPuedes cambiar este acceso directo a otra función en Configuración > Accesibilidad."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"No activar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e64f568..834c901 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar la configuración de audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que la aplicación modifique la configuración de audio global (por ejemplo, el volumen y el altavoz de salida)."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabar sonido"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta aplicación puede grabar audio con el micrófono en cualquier momento."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Este permiso es muy peligroso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta aplicación puede reconocer tu actividad física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"realizar fotografías y vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Esta aplicación puede hacer fotografías y grabar vídeos con la cámara en cualquier momento."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que una aplicación o servicio acceda a las cámaras del sistema para hacer fotos y vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación del sistema o con privilegios puede hacer fotos y grabar vídeos en cualquier momento con una cámara del sistema, aunque debe tener también el permiso android.permission.CAMERA para hacerlo"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que una aplicación o servicio reciba retrollamadas cada vez que se abra o cierre una cámara."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar el acceso directo a las funciones de accesibilidad?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Al mantener pulsadas las dos teclas de volumen durante unos segundos, se activan las funciones de accesibilidad, que pueden cambiar el funcionamiento del dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Ajustes > Accesibilidad."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes > Accesibilidad."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"No activar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index a3622d64..babd58d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"muuda heliseadeid"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Võimaldab rakendusel muuta üldiseid heliseadeid, näiteks helitugevust ja seda, millist kõlarit kasutatakse väljundiks."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"salvesta heli"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"See rakendus saab mikrofoni kasutades mis tahes ajal heli salvestada."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-kaardile käskluste saatmine"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lubab rakendusel saata käske SIM-kaardile. See on väga ohtlik."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"füüsiliste tegevuste tuvastamine"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"See rakendus saab tuvastada teie füüsilised tegevused."</string>
<string name="permlab_camera" msgid="6320282492904119413">"piltide ja videote tegemine"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"See rakendus saab mis tahes ajal kaameraga pildistada ja videoid salvestada."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Rakendusel või teenusel lubatakse süsteemi kaameratele juurde pääseda, et pilte ja videoid jäädvustada"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"See privileegidega või süsteemirakendus saab süsteemi kaameraga alati pilte ja videoid jäädvustada. Rakendusel peab olema ka luba android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lubab rakendusel või teenusel kaameraseadmete avamise või sulgemise kohta tagasikutseid vastu võtta."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kas lülitada juurdepääsufunktsioonide otsetee sisse?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hoidke juurdepääsufunktsioonide sisselülitamiseks mõlemat helitugevuse klahvi mõni sekund all. See võib teie seadme tööviisi muuta.\n\nPraegused funktsioonid:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nValitud funktsioone saab muuta jaotises Seaded > Juurdepääsetavus."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kas lülitada teenuse <xliff:g id="SERVICE">%1$s</xliff:g> otsetee sisse?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Kui hoiate mõlemat helitugevuse klahvi mõni sekund all, lülitatakse juurdepääsufunktsioon <xliff:g id="SERVICE">%1$s</xliff:g> sisse. See võib teie seadme tööviisi muuta.\n\nSelle otsetee saab asendada muu otseteega jaotises Seaded > Juurdepääsetavus."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Lülita sisse"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ära lülita sisse"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 47d41f5..3ba099b 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"aldatu audio-ezarpenak"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Audio-ezarpen orokorrak aldatzeko baimena ematen dio; besteak beste, bolumena eta irteerarako zer bozgorailu erabiltzen den."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabatu audioa"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Aplikazioak edonoiz erabil dezake mikrofonoa audioa grabatzeko."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"bidali aginduak SIM txartelera"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM txartelera aginduak bidaltzeko aukera ematen die aplikazioei. Oso arriskutsua da."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"hauteman ariketa fisikoa"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikazioak ariketa fisikoa hauteman dezake."</string>
<string name="permlab_camera" msgid="6320282492904119413">"atera argazkiak eta grabatu bideoak"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"onartu aplikazio edo zerbitzu bati sistemako kamerak atzitzea argazkiak eta bideoak ateratzeko"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erabilerraztasun-eginbideetarako lasterbidea aktibatu nahi duzu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Eduki sakatuta bolumen-botoiak segundo batzuez erabilerraztasun-eginbideak aktibatzeko. Hori eginez gero, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nUneko eginbideak:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nHautatutako eginbideak aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> zerbitzuaren lasterbidea aktibatu nahi duzu?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Eduki sakatuta bolumen-botoiak segundo batzuez <xliff:g id="SERVICE">%1$s</xliff:g> izeneko erabilerraztasun-eginbidea aktibatzeko. Honen bidez, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nLasterbide hau beste eginbide batengatik aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktibatu"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ez aktibatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 807a7ae..7750d5d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"این برنامه میتواند در هرزمانی با استفاده از میکروفون صدا ضبط کند."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ارسال فرمان به سیم کارت"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"به برنامه اجازه ارسال دستورات به سیم کارت را میدهد. این بسیار خطرناک است."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"تشخیص فعالیت فیزیکی"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"این برنامه نمیتواند فعالیت فیزیکیتان را تشخیص دهد."</string>
<string name="permlab_camera" msgid="6320282492904119413">"عکسبرداری و فیلمبرداری"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"این برنامه میتواند در هرزمانی با استفاده از دوربین عکس و فیلم بگیرد."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"به برنامه یا سرویسی اجازه دهید برای عکسبرداری و فیلمبرداری به دوربینهای سیستم دسترسی داشته باشد"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"این برنامه سیستم یا دارای امتیاز، میتواند با استفاده از دوربین سیستم در هرزمانی عکسبرداری و فیلمبرداری کند. برنامه به اجازه android.permission.CAMERA هم نیاز دارد."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"مجاز کردن برنامه یا سرویس برای دریافت پاسخ تماس درباره دستگاههای دوربینی که باز یا بسته میشوند."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش میدهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی میتواند به شنواییتان آسیب وارد کند."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"از میانبر دسترسپذیری استفاده شود؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"وقتی میانبر روشن باشد، با فشار دادن هردو دکمه صدا بهمدت ۳ ثانیه ویژگی دسترسپذیری فعال میشود."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"میانبر برای ویژگیهای دسترسپذیری روشن شود؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"با پایین نگه داشتن هردو کلید میزان صدا بهمدت چند ثانیه، ویژگیهای دسترسپذیری روشن میشود. با این کار نحوه عملکرد دستگاهتان تغییر میکند.\n\nویژگیهای فعلی:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nمیتوانید ویژگیهای انتخابی را در «تنظیمات > دسترسپذیری» تغییر دهید."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"میانبر <xliff:g id="SERVICE">%1$s</xliff:g> روشن شود؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"با پایین نگه داشتن هردو کلید میزان صدا بهمدت چند ثانیه، <xliff:g id="SERVICE">%1$s</xliff:g> (یکی از ویژگیهای دسترسپذیری) روشن میشود. با این کار نحوه عملکرد دستگاهتان تغییر میکند.\n\nمیتوانید در «تنظیمات > دسترسپذیری»،این میانبر را به ویژگی دیگری تغییر دهید."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"روشن شود"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"روشن نشود"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index da7ab3c..616223b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"muuta ääniasetuksia"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Antaa sovelluksen muokata yleisiä ääniasetuksia, kuten äänenvoimakkuutta ja käytettävää kaiutinta."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"tallentaa ääntä"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Tämä sovellus voi tallentaa mikrofonilla ääntä koska tahansa."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"lähettää komentoja SIM-kortille"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Antaa sovelluksen lähettää komentoja SIM-kortille. Tämä ei ole turvallista."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"tunnistaa liikkumisen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Sovellus voi tunnistaa liikkumisesi."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ota kuvia ja videoita"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Tämä sovellus voi ottaa kameralla kuvia ja videoita koska tahansa."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Salli sovellukselle tai palvelulle pääsy järjestelmän kameroihin, jotta se voi ottaa kuvia ja nauhoittaa videoita"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tämä oikeutettu tai järjestelmäsovellus voi ottaa järjestelmän kameralla kuvia ja videoita koska tahansa. Sovelluksella on oltava myös android.permission.CAMERA-lupa"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Salli sovelluksen tai palvelun vastaanottaa vastakutsuja kameralaitteiden avaamisesta tai sulkemisesta."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Laitetaanko esteettömyysominaisuuksien pikavalinta päälle?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Molempien äänenvoimakkuuspainikkeiden painaminen muutaman sekunnin ajan laittaa esteettömyysominaisuudet päälle. Tämä voi muuttaa laitteesi toimintaa.\n\nNykyiset ominaisuudet:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVoit muuttaa valittuja ominaisuuksia kohdassa Asetukset > Esteettömyys."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Laitetaanko pikavalinta (<xliff:g id="SERVICE">%1$s</xliff:g>) päälle?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Molempien äänenvoimakkuuspainikkeiden pitkään painaminen laittaa päälle esteettömyysominaisuuden <xliff:g id="SERVICE">%1$s</xliff:g>. Tämä voi muuttaa laitteesi toimintaa.\n\nVoit muuttaa tätä pikanäppäintä kohdassa Asetukset > Esteettömyys."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Laita päälle"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Älä laita päälle"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d44f036..6111270 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifier vos paramètres audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"enregistrer des fichiers audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Cette application peut enregistrer de l\'audio à l\'aide du microphone en tout temps."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître les activités physiques"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette application peut reconnaître vos activités physiques."</string>
<string name="permlab_camera" msgid="6320282492904119413">"prendre des photos et filmer des vidéos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo en tout temps."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une application ou un service à accéder aux appareils photo système pour prendre des photos et filmer des vidéos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'application doit également posséder l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour les fonctionnalités d\'accessibilité?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez les fonctionnalités d\'accessibilité. Cela peut modifier le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, sélectionnez Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci pour <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut modifier le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, sélectionnez Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ne pas activer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 57040d0..fa991a9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifier vos paramètres audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"enregistrer des fichiers audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Cette application peut utiliser le micro pour enregistrer du contenu audio à tout moment."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Autoriser l\'envoi de commandes à la carte SIM via l\'application. Cette fonctionnalité est très risquée."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître l\'activité physique"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette application peut reconnaître votre activité physique."</string>
<string name="permlab_camera" msgid="6320282492904119413">"prendre des photos et enregistrer des vidéos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Cette application peut utiliser l\'appareil photo pour prendre des photos et enregistrer des vidéos à tout moment."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une application ou un service à accéder aux caméras système pour prendre des photos et enregistrer des vidéos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut utiliser une caméra photo système pour prendre des photos et enregistrer des vidéos à tout moment. Pour cela, l\'application doit également disposer de l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service à recevoir des rappels liés à l\'ouverture ou à la fermeture de caméras"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour démarrer une fonctionnalité d\'accessibilité."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour accéder aux fonctionnalités d\'accessibilité ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez des fonctionnalités d\'accessibilité. Cela peut affecter le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, accédez à Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci <xliff:g id="SERVICE">%1$s</xliff:g> ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut affecter le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, accédez à Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ne pas activer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 581dda5..115850a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar a configuración de son"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite á aplicación modificar a configuración de audio global, como o volume e que altofalante se utiliza para a saída."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta aplicación pode utilizar o micrófono en calquera momento para gravar audio."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos á SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite á aplicación enviar comandos á SIM. Isto é moi perigoso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recoñecer actividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta aplicación pode recoñecer a túa actividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"facer fotos e vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Esta aplicación pode utilizar a cámara en calquera momento para sacar fotos e gravar vídeos."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que unha aplicación ou un servizo acceda ás cámaras do sistema para sacar fotos e gravar vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación do sistema con privilexios pode utilizar unha cámara do sistema en calquera momento para tirar fotos e gravar vídeos. Require que a aplicación tamén teña o permiso android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que unha aplicación ou servizo reciba retrochamadas cando se abran ou se pechen dispositivos con cámara."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Queres activar as funcións de accesibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ao manter as dúas teclas de volume premidas durante uns segundos actívanse as funcións de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nFuncións activadas actualmente:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPodes cambiar as funcións seleccionadas en Configuración > Accesibilidade."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Queres activar o atallo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ao manter as dúas teclas de volume premidas durante uns segundos actívase <xliff:g id="SERVICE">%1$s</xliff:g>, unha función de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nPodes cambiar o uso deste atallo para outra función en Configuración > Accesibilidade."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Non activar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index c95b8eb..918a6ff 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"આ ઍપ્લિકેશન, માઇક્રોફોનનો ઉપયોગ કરીને કોઈપણ સમયે ઑડિઓ રેકોર્ડ કરી શકે છે."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"સિમ ને આદેશો મોકલો"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"એપ્લિકેશનને સિમ પરા આદેશો મોકલવાની મંજૂરી આપે છે. આ ખૂબ જ ખતરનાક છે."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"શારીરિક પ્રવૃત્તિને ઓળખો"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"આ ઍપ તમારી શારીરિક પ્રવૃત્તિને ઓળખી શકે છે."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ચિત્રો અને વિડિઓઝ લો"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"આ ઍપ્લિકેશન, કૅમેરાનો ઉપયોગ કરીને કોઈપણ સમયે ચિત્રો લઈ અને વિડિઓઝ રેકોર્ડ કરી શકે છે."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ઍપ્લિકેશન અથવા સેવા ઍક્સેસને સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા અને વીડિયો લેવાની મંજૂરી આપો"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"આ વિશેષાધિકૃત અથવા સિસ્ટમ ઍપ કોઈપણ સમયે સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા લઈ અને વીડિયો રેકૉર્ડ કરી શકે છે. ઍપ દ્વારા આયોજિત કરવા માટે android.permission.CAMERAની પરવાનગી પણ જરૂરી છે"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"કૅમેરા ડિવાઇસ ચાલુ કે બંધ થવા વિશે કૉલબૅક પ્રાપ્ત કરવાની ઍપ્લિકેશન કે સેવાને મંજૂરી આપો."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરીએ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ઍક્સેસિબિલિટી સુવિધાઓ માટે શૉર્ટકટ ચાલુ કરીએ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધાઓ ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nવર્તમાન સુવિધાઓ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nતમે સેટિંગ > ઍક્સેસિબિલિટીમાં જઈને પસંદ કરેલી સુવિધાઓને બદલી શકો છો."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> શૉર્ટકટ ચાલુ કરીએ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા એવી <xliff:g id="SERVICE">%1$s</xliff:g> ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nતમે સેટિંગ > ઍક્સેસિબિલિટીમાં જઈને આ શૉર્ટકટને બીજી સુવિધામાં બદલી શકો છો."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ચાલુ કરો"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ચાલુ કરશો નહીં"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b56fa2c..db049b1 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"यह ऐप्लिकेशन किसी भी समय माइक्रोफ़ोन का उपयोग करके ऑडियो रिकॉर्ड कर सकता है."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"सिम पर निर्देश भेजें"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ऐप को सिम पर निर्देश भेजने देती है. यह बहुत ही खतरनाक है."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शरीर की गतिविधि को पहचानना"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यह ऐप्लिकेशन आपके शरीर की गतिविधि को पहचान सकता है."</string>
<string name="permlab_camera" msgid="6320282492904119413">"चित्र और वीडियो लें"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"यह ऐप्लिकेशन किसी भी समय कैमरे का उपयोग करके चित्र ले सकता है और वीडियो रिकॉर्ड कर सकता है."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"तस्वीरें और वीडियो लेने के लिए ऐप्लिकेशन या सेवा को सिस्टम के कैमरे का ऐक्सेस दें"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"यह खास सिस्टम ऐप्लिकेशन जब चाहे, तस्वीरें लेने और वीडियो रिकॉर्ड करने के लिए सिस्टम के कैमरे का इस्तेमाल कर सकता है. इसके लिए ऐप्लिकेशन को android.permission.CAMERA की अनुमति देना भी ज़रूरी है"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"डिवाइस का कैमरे चालू या बंद होने पर, किसी ऐप्लिकेशन या सेवा को कॉलबैक पाने की मंज़ूरी दें."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर ज़्यादा समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"सुलभता शॉर्टकट का इस्तेमाल करना चाहते हैं?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट के चालू होने पर, दाेनाें वॉल्यूम बटन (आवाज़ कम या ज़्यादा करने वाले बटन) को तीन सेकंड तक दबाने से, सुलभता सुविधा शुरू हाे जाएगी."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"क्या आप सुलभता सुविधाओं के लिए शॉर्टकट चालू करना चाहते हैं?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से सुलभता सुविधाएं चालू हो जाती हैं. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nमौजूदा सुविधाएं:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nआप सेटिंग और सुलभता में जाकर चुनी हुई सुविधाएं बदल सकते हैं."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"क्या आप <xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट चालू करना चाहते हैं?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से <xliff:g id="SERVICE">%1$s</xliff:g> चालू हो जाती है, जो एक सुलभता सुविधा है. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nआप सेटिंग और सुलभता में जाकर इस शॉर्टकट को किसी दूसरी सुविधा के लिए बदल सकते हैं."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"चालू करें"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"चालू न करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2678cb8..b9b3665 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -435,13 +435,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"promjena postavki zvuka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Aplikaciji omogućuje izmjenu globalnih postavki zvuka, primjerice glasnoće i zvučnika koji se upotrebljava za izlaz."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje zvuka"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Aplikacija u svakom trenutku može snimati zvuk mikrofonom."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"slati naredbe SIM-u"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućuje aplikaciji slanje naredbi SIM-u. To je vrlo opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznati tjelesnu aktivnost"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može prepoznati vašu tjelesnu aktivnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimi fotografije i videozapise"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Aplikacija u svakom trenutku može snimati fotografije i videozapise fotoaparatom."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dopustite aplikaciji ili usluzi da pristupa kamerama sustava radi snimanja fotografija i videozapisa"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena aplikacija ili aplikacija sustava u svakom trenutku može snimati fotografije i videozapise kamerom sustava. Aplikacija mora imati i dopuštenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dopustite aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju fotoaparata."</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad je taj prečac uključen, pritiskom na obje tipke za glasnoću na tri sekunde pokrenut će se značajka pristupačnosti."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite li uključiti prečac za značajke pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Značajke pristupačnosti uključuju se ako na nekoliko sekundi pritisnete obje tipke za glasnoću. Time se može promijeniti način na koji vaš uređaj radi.\n\nTrenutačne značajke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane značajke možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite li uključiti prečac za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako na nekoliko sekundi pritisnete obje tipke za glasnoću, uključuje se značajka pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Time se može promijeniti način na koji vaš uređaj radi.\n\nZnačajku na koju se taj prečac odnosi možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nemoj uključiti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 235c8fd..16d60dc 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"hangbeállítások módosítása"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lehetővé teszi az alkalmazás számára az általános hangbeállítások, például a hangerő és a használni kívánt kimeneti hangszóró módosítását."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"hanganyag rögzítése"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Az alkalmazás a mikrofon használatával bármikor készíthet hangfelvételt."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"parancsok küldése a SIM-kártyára"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Engedélyezi, hogy az alkalmazás parancsokat küldjön a SIM kártyára. Ez rendkívül veszélyes lehet."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"testmozgás felismerése"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Az alkalmazás képes felismerni a testmozgást."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotók és videók készítése"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Az alkalmazás a kamera használatával bármikor készíthet fényképeket és rögzíthet videókat."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"A rendszerkamerákhoz való hozzáférés, illetve képek és videók rögzítésének engedélyezése alkalmazás vagy szolgáltatás számára"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"A rendszerkamera használatával ez az előnyben részesített vagy rendszeralkalmazás bármikor készíthet fényképeket és videókat. Az alkalmazásnak az „android.permission.CAMERA” engedéllyel is rendelkeznie kell."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Visszahívás fogadásának engedélyezése alkalmazás vagy szolgáltatás számára, ha a kamerákat megnyitják vagy bezárják."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ha a gyorsparancs aktív, akkor a két hangerőgomb három másodpercig tartó együttes lenyomásával kisegítő funkciót indíthat el."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bekapcsol gyorsparancsot a kisegítő lehetőségekhez?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"A kisegítő lehetőségek bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nJelenlegi funkciók:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nA kiválasztott funkciókat a Beállítások > Kisegítő lehetőségek pontban módosíthatja."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bekapcsolja a(z) <xliff:g id="SERVICE">%1$s</xliff:g> szolgáltatás gyorsparancsát?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"A(z) <xliff:g id="SERVICE">%1$s</xliff:g> kisegítő lehetőség bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nEzt a gyorsparancsot a Beállítások > Kisegítő lehetőségek pontban módosíthatja másik funkció használatára."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bekapcsolom"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nem kapcsolom be"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 3634908..aa4197f 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Այս հավելվածը ցանկացած պահի կարող է ձայնագրել խոսափողի օգնությամբ:"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ուղարկել հրամաններ SIM քարտին"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Թույլ է տալիս հավելվածին հրամաններ ուղարկել SIM-ին: Սա շատ վտանգավոր է:"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ֆիզիկական ակտիվության ճանաչում"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Հավելվածը կարող է ճանաչել ձեր ֆիզիկական ակտիվությունը:"</string>
<string name="permlab_camera" msgid="6320282492904119413">"լուսանկարել և տեսանկարել"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Այս հավելվածը կարող է ցանկացած պահի լուսանկարել և տեսագրել՝ օգտագործելով տեսախցիկը:"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Թույլատրել որևէ հավելվածի կամ ծառայության օգտագործել համակարգի տեսախցիկները՝ լուսանկարելու և տեսանկարելու համար"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Այս արտոնյալ կամ համակարգային հավելվածը կարող է ցանկացած պահի լուսանկարել և տեսագրել՝ օգտագործելով համակարգի տեսախցիկները։ Հավելվածին նաև անհրաժեշտ է android.permission.CAMERA թույլտվությունը։"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Թույլատրել հավելվածին կամ ծառայությանը հետզանգեր ստանալ՝ տեսախցիկների բացվելու և փակվելու դեպքում։"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Միացնե՞լ հատուկ գործառույթների դյուրանցումը"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք հատուկ գործառույթները։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԸնթացիկ գործառույթներ՝\n<xliff:g id="SERVICE">%1$s</xliff:g>\nԸնտրված գործառույթները փոխելու համար անցեք Կարգավորումներ > Հատուկ գործառույթներ։"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Միացնե՞լ <xliff:g id="SERVICE">%1$s</xliff:g>-ի դյուրանցումը"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք <xliff:g id="SERVICE">%1$s</xliff:g> ծառայությունը, որը հատուկ գործառույթ է։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԱյս դյուրանցումը մեկ այլ գործառույթով փոխելու համար անցեք Կարգավորումներ > Հատուկ գործառույթներ։"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Միացնել"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Չմիացնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5974594..3e6c23e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ubah setelan audio Anda"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Memungkinkan aplikasi mengubah setelan audio global, misalnya volume dan pengeras suara mana yang digunakan untuk keluaran."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"rekam audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Aplikasi ini dapat merekam audio menggunakan mikrofon kapan saja."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"kirimkan perintah ke SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Mengizinkan aplikasi mengirim perintah ke SIM. Ini sangat berbahaya."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"kenali aktivitas fisik"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikasi ini dapat mengenali aktivitas fisik Anda."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ambil gambar dan video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Aplikasi ini dapat mengambil foto dan merekam video menggunakan kamera kapan saja."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Izinkan akses aplikasi atau layanan ke kamera sistem untuk mengambil gambar dan video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aplikasi sistem atau yang diberi hak istimewa ini dapat mengambil gambar dan merekam video menggunakan kamera sistem kapan saja. Mewajibkan aplikasi untuk memiliki izin android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Izinkan aplikasi atau layanan untuk menerima callback tentang perangkat kamera yang sedang dibuka atau ditutup."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Aktifkan pintasan untuk fitur aksesibilitas?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nFitur saat ini:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda dapat mengubah fitur yang dipilih di Setelan > Aksesibilitas."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Aktifkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan <xliff:g id="SERVICE">%1$s</xliff:g>, yang merupakan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nAnda dapat mengubah pintasan ini ke fitur lain di Setelan > Aksesibilitas."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktifkan"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Jangan aktifkan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 64e855f..272145d 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"breyta hljóðstillingum"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Leyfir forriti að breyta altækum hljóðstillingum, s.s. hljóðstyrk og hvaða hátalari er notaður sem úttak."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"taka upp hljóð"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Þetta forrit getur tekið upp hljóð með hljóðnemanum hvenær sem er."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"senda skipanir til SIM-kortsins"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Leyfir forriti að senda SIM-kortinu skipanir. Þetta er mjög hættulegt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"greina hreyfingu"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Þetta forrit getur greint hreyfingu þína."</string>
<string name="permlab_camera" msgid="6320282492904119413">"taka myndir og myndskeið"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Þetta forrit getur tekið myndir og tekið upp myndskeið með myndavélinni hvenær sem er."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Veittu forriti eða þjónustu aðgang að myndavélum kerfis til að taka myndir og myndskeið"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Þetta forgangs- eða kerfisforrit hefur heimild til að taka myndir og taka upp myndskeið með myndavél kerfisins hvenær sem er. Forritið þarf einnig að vera með heimildina android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leyfa forriti eða þjónustu að taka við svörum um myndavélar sem verið er að opna eða loka."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kveikja á flýtileið fyrir aðgangseiginleika?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Kveikt er á aðgengiseiginleikum þegar báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur. Þetta getur breytt því hvernig tækið virkar.\n\nNúverandi eiginleikar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÞú getur breytt völdum eiginleikum í Stillingar > Aðgengi."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kveikja á flýtileið <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ef báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur er kveikt á aðgengiseiginleikanum <xliff:g id="SERVICE">%1$s</xliff:g>. Þetta getur breytt því hvernig tækið virkar.\n\nÞú getur breytt þessari flýtileið í annan eiginleika í Stillingar > Aðgengi."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Kveikja"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ekki kveikja"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 185bdcf..9970915 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifica impostazioni audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"registrazione audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Questa app può registrare audio tramite il microfono in qualsiasi momento."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"invio di comandi alla SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"riconoscimento dell\'attività fisica"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Questa app può riconoscere la tua attività fisica."</string>
<string name="permlab_camera" msgid="6320282492904119413">"acquisizione di foto e video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Questa app può scattare foto e registrare video tramite la fotocamera in qualsiasi momento."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Consenti a un\'applicazione o a un servizio di accedere alle videocamere del sistema per fare foto e video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Questa app di sistema o con privilegi può scattare foto e registrare video tramite una videocamera di sistema in qualsiasi momento. Richiede che anche l\'app disponga dell\'autorizzazione android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Consenti a un\'applicazione o a un servizio di ricevere callback relativi all\'apertura o alla chiusura di videocamere."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vuoi attivare la scorciatoia per le funzioni di accessibilità?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Se tieni premuti entrambi i tasti del volume per qualche secondo, vengono attivate le funzioni di accessibilità. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nFunzioni correnti:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuoi modificare le funzioni selezionate in Impostazioni > Accessibilità."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vuoi attivare la scorciatoia per <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Se tieni premuti entrambi i tasti del volume per qualche secondo verrà attivata la funzione di accessibilità <xliff:g id="SERVICE">%1$s</xliff:g>. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nPuoi associare questa scorciatoia a un\'altra funzionalità in Impostazioni > Accessibilità."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Attiva"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Non attivare"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 963489e..e8413d6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -438,13 +438,23 @@
<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="3976213377904701093">"אפליקציה זו יכולה להשתמש במיקרופון כדי להקליט אודיו בכל עת."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"שליחת פקודות אל ה-SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"מאפשרת ליישום לשלוח פקודות ל-SIM. זוהי הרשאה מסוכנת מאוד."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"זיהוי הפעילות הגופנית"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"האפליקציה מזהה את הפעילות הגופנית שלך."</string>
<string name="permlab_camera" msgid="6320282492904119413">"צלם תמונות וסרטונים"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"אפליקציה זו יכולה להשתמש במצלמה כדי לצלם תמונות ולהקליט סרטונים בכל עת."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"הרשאת גישה לאפליקציה או לשירות למצלמות המערכת כדי לצלם תמונות וסרטונים"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"אפליקציה זו בעלת ההרשאות, או אפליקציית המערכת הזו, יכולה לצלם תמונות ולהקליט סרטונים באמצעות מצלמת מערכת בכל זמן. בנוסף, לאפליקציה נדרשת ההרשאה android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"אפליקציה או שירות יוכלו לקבל קריאות חוזרות (callback) כשמכשירי מצלמה ייפתחו או ייסגרו."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"האם להפעיל את מקש הקיצור לתכונות הנגישות?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"לחיצה ארוכה על שני לחצני עוצמת הקול למשך מספר שניות מפעילה את תכונות הנגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nהתכונות הנוכחיות:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nניתן לשנות תכונות נבחרות ב\'הגדרות\' > \'נגישות\'."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"האם להפעיל את מקש הקיצור של <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ניתן ללחוץ על שני מקשי עוצמת הקול למשך מספר שניות כדי להפעיל את <xliff:g id="SERVICE">%1$s</xliff:g>, תכונת נגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nאפשר לשנות את מקשי הקיצור האלה לתכונה נוספת ב\'הגדרות\' > \'נגישות\'."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"אני רוצה להפעיל"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"לא להפעיל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ee9f0eb..012ee3f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"このアプリは、いつでもマイクを使用して録音できます。"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMへのコマンド送信"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIMにコマンドを送信することをアプリに許可します。この許可は非常に危険です。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"身体活動の認識"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"このアプリで身体活動が認識されるようにします。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"写真と動画の撮影"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"このアプリは、いつでもカメラを使用して写真や動画を撮影できます。"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"写真と動画を撮影するには、システムカメラへのアクセスをアプリまたはサービスに許可してください"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"権限を付与されたこのアプリまたはシステムアプリは、いつでもシステムカメラを使用して写真と動画を撮影できます。アプリには android.permission.CAMERA 権限も必要です"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"カメラデバイスが起動または終了したときにコールバックを受け取ることを、アプリまたはサービスに許可してください。"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ユーザー補助機能のショートカットを ON にしますか?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\n現在の機能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n選択した機能は [設定] > [ユーザー補助] で変更できます。"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> のショートカットを ON にしますか?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能の <xliff:g id="SERVICE">%1$s</xliff:g> が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\nこのショートカットは [設定] > [ユーザー補助] で別の機能に変更できます。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ON にする"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ON にしない"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 72d9374..f6e8f5d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ამ აპს ნებისმიერ დროს შეუძლია მიკროფონით აუდიოს ჩაწერა."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ბრძანებების SIM-ზე გაგზავნა"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"აპისთვის ნების დართვა გაუგზავნოს ბრძანებები SIM-ბარათს. ეს ძალიან საშიშია."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ფიზიკური აქტივობის ამოცნობა"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ამ აპს შეუძლია თქვენი ფიზიკური აქტივობის ამოცნობა."</string>
<string name="permlab_camera" msgid="6320282492904119413">"სურათებისა და ვიდეოების გადაღება"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ამ აპს ნებისმიერ დროს შეუძლია კამერით სურათების გადაღება და ვიდეოების ჩაწერა."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ნება დაერთოს აპლიკაციას ან სერვისს, ჰქონდეს წვდომა სისტემის კამერებზე სურათების და ვიდეოების გადასაღებად"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ამ პრივილეგირებულ ან სისტემის აპს შეუძლია ფოტოების გადაღება და ვიდეოების ჩაწერა ნებისმიერ დროს სისტემის კამერის გამოყენებით. საჭიროა, რომ აპს ჰქოდეს android.permission.CAMERA ნებართვაც"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ნება დაერთოს აპლიკაციას ან სერვისს, მიიღოს გადმორეკვები კამერის მოწყობილობის გახსნის ან დახურვისას."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"გსურთ მარტივი წვდომის მალსახმობის გამოყენება?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"თუ მალსახმობი ჩართულია, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ჩაირთოს მარტივი წვდომის ფუნქციების მალსახმობი?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ხმის ორივე ღილაკზე ხანგრძლივად დაჭერა რამდენიმე წამის განმავლობაში ჩართავს მარტივი წვდომის ფუნქციებს. ამ ქმედებამ შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამჟამინდელი ფუნქციები:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nარჩეული ფუნქციების შეცვლა შესაძლებელია აქ: პარამეტრები > მარტივი წვდომა."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ჩაირთოს <xliff:g id="SERVICE">%1$s</xliff:g>-ის მალსახმობი?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ხმის ორივე ღილაკზე რამდენიმე წამის განმავლობაში დაჭერით ჩაირთვება <xliff:g id="SERVICE">%1$s</xliff:g>, რომელიც მარტივი წვდომის ფუნქციაა. ამან შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამ მალსახმობის შეცვლა სხვა ფუნქციით შეგიძლიათ აქ: პარამეტრები > აპები."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ჩართვა"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"არ ჩაირთოს"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index ca1500d..b0d363c 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Бұл қолданба кез келген уақытта микрофон арқылы аудиомазмұн жаза алады."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM картасына пәрмендер жіберу"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Қолданбаға SIM картасына пәрмен жіберу мүмкіндігін береді. Бұл өте қауіпті."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"физикалық әрекетті тану"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Бұл қолданба физикалық әрекетті тани алады."</string>
<string name="permlab_camera" msgid="6320282492904119413">"фотосурет жасау және бейне жазу"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Бұл қолданба кез келген уақытта камерамен суретке түсіруі және бейнелерді жазуы мүмкін."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Суретке немесе бейнеге түсіру үшін қолданбаға немесе қызметке жүйелік камераларды пайдалануға рұқсат беру"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Осы айрықша немесе жүйе қолданбасы кез келген уақытта жүйелік камера арқылы суретке не бейнеге түсіре алады. Қолданбаға android.permission.CAMERA рұқсаты қажет болады."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Қолданбаға не қызметке ашылып не жабылып жатқан камера құрылғылары туралы кері шақыру алуға рұқсат ету"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Арнайы мүмкіндіктердің жылдам пәрмені іске қосылсын ба?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, арнайы мүмкіндіктер іске қосылады. Бұл – құрылғының жұмысына әсер етуі мүмкін.\n\nҚазіргі функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТаңдалған функцияларды \"Параметрлер > Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> жылдам пәрмені іске қосылсын ба?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, <xliff:g id="SERVICE">%1$s</xliff:g> арнайы қызметі іске қосылады. Бұл – құрылғының жүмысына әсер етуі мүмкін.\n\nБұл таңбашаны басқа функцияға \"Параметрлер > Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Қосылсын"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Қосылмасын"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4424426..a16251d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"កម្មវិធីនេះអាចថតសំឡេងដោយប្រើមីក្រូហ្វូនបានគ្រប់ពេល។"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ផ្ញើពាក្យបញ្ជាទៅស៊ីមកាត"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ឲ្យកម្មវិធីផ្ញើពាក្យបញ្ជាទៅស៊ីមកាត។ វាគ្រោះថ្នាក់ណាស់។"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ស្គាល់សកម្មភាពរាងកាយ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"កម្មវិធីនេះអាចស្គាល់សកម្មភាពរាងកាយរបស់អ្នក។"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ថតរូប និងវីដេអូ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"កម្មវិធីនេះអាចថតរូប និងថតវីដេអូ ដោយប្រើកាមេរ៉ាបានគ្រប់ពេល។"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្មចូលប្រើកាមេរ៉ាប្រព័ន្ធ ដើម្បីថតរូប និងថតវីដេអូ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"កម្មវិធីប្រព័ន្ធ ឬកម្មវិធីដែលមានសិទ្ធិអនុញ្ញាតនេះអាចថតរូប និងថតវីដេអូ ដោយប្រើកាមេរ៉ាប្រព័ន្ធបានគ្រប់ពេល។ តម្រូវឱ្យមានការអនុញ្ញាត android.permission.CAMERA ដើម្បីឱ្យកម្មវិធីអាចធ្វើសកម្មភាពបានផងដែរ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្មទទួលការហៅត្រឡប់វិញអំពីកាមេរ៉ាដែលកំពុងបិទ ឬបើក។"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"បង្កើនកម្រិតសំឡេងលើសពីកម្រិតបានផ្ដល់យោបល់?\n\nការស្ដាប់នៅកម្រិតសំឡេងខ្លាំងយូរអាចធ្វើឲ្យខូចត្រចៀក។"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ប្រើប្រាស់ផ្លូវកាត់ភាពងាយស្រួល?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"នៅពេលបើកផ្លូវកាត់ ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីររយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយប្រើ។"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"បើកផ្លូវកាត់សម្រាប់មុខងារភាពងាយស្រួលឬ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ការសង្កត់គ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលពីរបីវិនាទីនឹងបើកមុខងារភាពងាយប្រើ។ ការធ្វើបែបនេះអាចផ្លាស់ប្ដូររបៀបដែលឧបករណ៍របស់អ្នកដំណើរការ។\n\nមុខងារបច្ចុប្បន្ន៖\n<xliff:g id="SERVICE">%1$s</xliff:g>\nអ្នកអាចប្ដូរមុខងារដែលបានជ្រើសរើសនៅក្នុងការកំណត់ > ភាពងាយស្រួល។"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"បើកផ្លូវកាត់ <xliff:g id="SERVICE">%1$s</xliff:g> ឬ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ការសង្កត់គ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលពីរបីវិនាទីនឹងបើក <xliff:g id="SERVICE">%1$s</xliff:g> ដែលជាមុខងារភាពងាយប្រើ។ ការធ្វើបែបនេះអាចផ្លាស់ប្ដូររបៀបដែលឧបករណ៍របស់អ្នកដំណើរការ។\n\nអ្នកអាចប្ដូរផ្លូវកាត់នេះទៅមុខងារផ្សេងទៀតនៅក្នុងការកំណត់ > ភាពងាយស្រួល។"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"បើក"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"កុំបើក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4e2e7e0..58ecb62 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವ ಮೂಲಕ ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ಸಿಮ್ಗೆ ಆಜ್ಞೆಗಳನ್ನು ಕಳುಹಿಸಿ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ಸಿಮ್ ಗೆ ಆದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ತುಂಬಾ ಅಪಾಯಕಾರಿ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಿ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ಈ ಆ್ಯಪ್ ನಿಮ್ಮ ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಬಹುದು."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಯಾವ ಸಮಯದಲ್ಲಾದರೂ ಕ್ಯಾಮರಾ ಬಳಸಿಕೊಂಡು ಚಿತ್ರಗಳು ಮತ್ತು ವಿಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಸಿಸ್ಟಂ ಕ್ಯಾಮರಾಗಳಿಗೆ ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸೇವಾ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ಈ ವಿಶೇಷ ಅಥವಾ ಸಿಸ್ಟಂ ಆ್ಯಪ್, ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಸಿಸ್ಟಂ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಟೋಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ವೀಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು. ಆ್ಯಪ್ಗೆ android.permission.CAMERA ಅನುಮತಿಯ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ಕ್ಯಾಮರಾ ಸಾಧನಗಳನ್ನು ತೆರೆಯುತ್ತಿರುವ ಅಥವಾ ಮುಚ್ಚುತ್ತಿರುವ ಕುರಿತು ಕಾಲ್ಬ್ಯಾಕ್ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಆ್ಯಪ್ ಅಥವಾ ಸೇವೆಗೆ ಅನುಮತಿಸಿ."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ವಾಲ್ಯೂಮ್ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಬಳಸುವುದೇ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಿದರೆ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವೊಂದು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳಿಗಾಗಿ ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳು ಆನ್ ಆಗುತ್ತವೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\n ಪ್ರಸ್ತುತ ವೈಶಿಷ್ಟ್ಯಗಳು:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿ ಆಯ್ದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನೀವು ಬದಲಾಯಿಸಬಹುದು."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ಶಾರ್ಟ್ಕಟ್ <xliff:g id="SERVICE">%1$s</xliff:g>ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವಾದ <xliff:g id="SERVICE">%1$s</xliff:g> ಆನ್ ಆಗುತ್ತದೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\nನೀವು ಈ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಅಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿನ ಮತ್ತೊಂದು ವೈಶಿಷ್ಟ್ಯಕ್ಕೆ ಬದಲಾಯಿಸಬಹುದು."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ಆನ್ ಮಾಡಿ"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ಆನ್ ಮಾಡಬೇಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 43c785a..394bd21 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"이 앱은 언제든지 마이크를 사용하여 오디오를 녹음할 수 있습니다."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM 카드로 명령 전송"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"앱이 SIM에 명령어를 전송할 수 있도록 허용합니다. 이 기능은 매우 신중히 허용해야 합니다."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"신체 활동 확인"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"이 앱에서 내 신체 활동을 확인할 수 있습니다."</string>
<string name="permlab_camera" msgid="6320282492904119413">"사진과 동영상 찍기"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"이 앱은 언제든지 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"사진 및 동영상 촬영을 위해 애플리케이션 또는 서비스에서 시스템 카메라에 액세스하도록 허용"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"이 권한이 있는 시스템 앱은 언제든지 시스템 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다. 또한 앱에 android.permission.CAMERA 권한이 필요합니다."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"애플리케이션 또는 서비스에서 카메라 기기 열림 또는 닫힘에 대한 콜백을 수신하도록 허용"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"접근성 기능 바로가기를 사용 설정하시겠습니까?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"볼륨 키 2개를 몇 초 동안 길게 누르면 접근성 기능이 사용 설정됩니다. 이때 기기 작동 방식이 달라질 수 있습니다.\n\n현재 기능:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n설정 > 접근성에서 선택한 기능을 변경할 수 있습니다."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> 바로가기를 사용 설정하시겠습니까?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"볼륨 키 2개를 몇 초 동안 길게 누르면 <xliff:g id="SERVICE">%1$s</xliff:g> 접근성 기능이 사용 설정됩니다. 이렇게 되면 기기 작동 방식이 달라질 수 있습니다.\n\n설정 > 접근성에서 이 단축키를 다른 기능으로 변경할 수 있습니다."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"사용"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"사용 안 함"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 182af1b..0774f6a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Бул колдонмо каалаган убакта микрофон менен аудио файлдарды жаздыра алат."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-картага буйруктарды жөнөтүү"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Колдонмого SIM-картага буйруктарды жөнөтүү мүмкүнчүлүгүн берет. Бул абдан кооптуу."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"кыймыл-аракетти аныктоо"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Бул колдонмо кыймыл-аракетиңизди аныктап турат."</string>
<string name="permlab_camera" msgid="6320282492904119413">"сүрөт жана видео тартуу"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Бул колдонмо каалаган убакта камера менен сүрөт же видеолорду тарта алат."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Сүрөткө тартып, видеолорду жаздыруу үчүн бул колдонмого же кызматка тутумдун камерасын колдонууга уруксат берүү"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Бул артыкчылыктуу тутум колдонмосу тутумдун камерасын каалаган убакта колдонуп, сүрөткө тартып, видео жаздыра алат. Ошондой эле колдонмого android.permission.CAMERA уруксатын берүү керек"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Колдонмого же кызматка камера ачылып же жабылып жатканда чалууларды кабыл алууга уруксат берүү."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн, үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн, үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Жок"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9f964eb..875d6817 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"This app can record audio using the microphone at any time."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ສົ່ງຄຳສັ່ງຫາ SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງຄຳສັ່ງຫາ SIM. ສິ່ງນີ້ອັນຕະລາຍຫຼາຍ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ຈຳແນກກິດຈະກຳທາງກາຍ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ແອັບນີ້ສາມາດຈັດລະບຽບການເຄື່ອນໄຫວທາງກາຍຂອງທ່ານໄດ້."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ຖ່າຍຮູບ ແລະວິດີໂອ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"This app can take pictures and record videos using the camera at any time."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການເຂົ້າເຖິງກ້ອງຂອງລະບົບໄດ້ເພື່ອຖ່າຍຮູບ ແລະ ວິດີໂອ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ສິດ ຫຼື ແອັບລະບົບນີ້ສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໂດຍໃຊ້ກ້ອງຂອງລະບົບຕອນໃດກໍໄດ້. ຕ້ອງໃຊ້ສິດອະນຸຍາດ android.permission.CAMERA ໃຫ້ແອັບຖືນຳ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການຮັບການເອີ້ນກັບກ່ຽວກັບອຸປະກອນກ້ອງຖືກເປີດ ຫຼື ປິດໄດ້."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ເພີ່ມລະດັບສຽງໃຫ້ເກີນກວ່າລະດັບທີ່ແນະນຳບໍ?\n\nການຮັບຟັງສຽງໃນລະດັບທີ່ສູງເປັນໄລຍະເວລາດົນອາດເຮັດໃຫ້ການຟັງຂອງທ່ານມີບັນຫາໄດ້."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ເມື່ອເປີດໃຊ້ທາງລັດແລ້ວ, ການກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີຈະເປັນການເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ເປີດໃຊ້ທາງລັດສຳລັບຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nຄຸນສົມບັດປັດຈຸບັນ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nທ່ານສາມາດປ່ຽນຄຸນສົມບັດທີ່ເລືອກໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ເປີດໃຊ້ທາງລັດ <xliff:g id="SERVICE">%1$s</xliff:g> ບໍ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ <xliff:g id="SERVICE">%1$s</xliff:g>, ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nທ່ານສາມາດປ່ຽນທາງລັດນີ້ເປັນຄຸນສົມບັດອື່ນໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ເປີດໃຊ້"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ບໍ່ເປີດ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 337b31c..a3e8391 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -438,13 +438,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"keisti garso nustatymus"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Leidžiama programai keisti visuotinius garso nustatymus, pvz., garsumą ir tai, kuris garsiakalbis naudojamas išvesčiai."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"įrašyti garsą"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ši programa gali bet kada įrašyti garsą naudodama mikrofoną."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"siųsti komandas į SIM kortelę"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Programai leidžiama siųsti komandas į SIM kortelę. Tai labai pavojinga."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"atpažinti fizinę veiklą"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ši programa gali atpažinti jūsų fizinę veiklą."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotografuoti ir filmuoti"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ši programa gali bet kada fotografuoti ir įrašyti vaizdo įrašų naudodama fotoaparatą."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Suteikti programai arba paslaugai prieigą prie sistemos fotoaparatų, kad būtų galima daryti nuotraukas ir įrašyti vaizdo įrašus"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ši privilegijuota arba sistemos programa gali daryti nuotraukas ir įrašyti vaizdo įrašus naudodama sistemos fotoaparatą bet kuriuo metu. Programai taip pat būtinas leidimas „android.permission.CAMERA“"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leisti programai ar paslaugai sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas fotoaparatas."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kai spartusis klavišas įjungtas, paspaudus abu garsumo mygtukus ir palaikius 3 sekundes bus įjungta pritaikymo neįgaliesiems funkcija."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Įjungti pritaikymo neįgaliesiems funkcijų spartųjį klavišą?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiamos pritaikymo neįgaliesiems funkcijos. Tai gali pakeisti įrenginio veikimą.\n\nDabartinės funkcijos:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPasirinktas funkcijas galite pakeisti skiltyje „Nustatymai“ > „Pritaikomumas“."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Įjungti „<xliff:g id="SERVICE">%1$s</xliff:g>“ spartųjį klavišą?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiama pritaikymo neįgaliesiems funkcija „<xliff:g id="SERVICE">%1$s</xliff:g>“. Tai gali pakeisti įrenginio veikimą.\n\nGalite pakeisti šį spartųjį klavišą į kitą funkciją skiltyje „Nustatymai“ > „Pritaikomumas“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Įjungti"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Neįjungti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 2b92b44..f086662 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -435,13 +435,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"mainīt audio iestatījumus"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ļauj lietotnei mainīt globālos audio iestatījumus, piemēram, skaļumu un izejai izmantoto skaļruni."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ierakstīt audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Šī lietotne jebkurā brīdī var ierakstīt audio, izmantojot mikrofonu."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"Sūtīt komandas SIM kartei"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ļauj lietotnei sūtīt komandas uz SIM karti. Tas ir ļoti bīstami!"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"noteikt fiziskās aktivitātes"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Šī lietotne var noteikt jūsu fiziskās aktivitātes."</string>
<string name="permlab_camera" msgid="6320282492904119413">"uzņemt attēlus un videoklipus"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Šī lietotne jebkurā brīdī var uzņemt attēlus un ierakstīt videoklipus, izmantojot kameru."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Atļauja lietojumprogrammai vai pakalpojumam piekļūt sistēmas kamerām, lai uzņemtu attēlus un videoklipus"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Šī privileģētā vai sistēmas lietotne var jebkurā brīdī uzņemt attēlus un ierakstīt videoklipus, izmantojot sistēmas kameru. Lietotnei nepieciešama arī atļauja android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Atļaut lietojumprogrammai vai pakalpojumam saņemt atzvanus par kameras ierīču atvēršanu vai aizvēršanu"</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad īsinājumtaustiņš ir ieslēgts, nospiežot abas skaļuma pogas un 3 sekundes turot tās, tiks aktivizēta pieejamības funkcija."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vai ieslēgt pieejamības funkciju saīsni?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgtas pieejamības funkcijas. Tas var mainīt ierīces darbību.\n\nPašreizējās funkcijas:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAtlasītās funkcijas varat mainīt šeit: Iestatījumi > Pieejamība."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vai ieslēgt <xliff:g id="SERVICE">%1$s</xliff:g> saīsni?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgta pieejamības funkcija <xliff:g id="SERVICE">%1$s</xliff:g>. Tas var mainīt ierīces darbību.\n\nŠo saīsni uz citu funkciju varat mainīt šeit: Iestatījumi > Pieejamība."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ieslēgt"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Neieslēgt"</string>
diff --git a/core/res/res/values-mcc310-mnc150-as/strings.xml b/core/res/res/values-mcc310-mnc150-as/strings.xml
new file mode 100644
index 0000000..2a4e46bd6
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me" msgid="8004509200390992737">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index ccd1ef7..b57307c 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Апликацијава може да снима аудио со микрофонот во секое време."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"испраќање наредби до SIM-картичката"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Овозможува апликацијата да испраќа наредби до SIM картичката. Ова е многу опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавајте ја физичката активност"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Апликацијава може да ја препознава вашата физичка активност."</string>
<string name="permlab_camera" msgid="6320282492904119413">"снимај слики и видеа"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Апликацијава може да фотографира и да снима видеа со камерата во секое време."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволете апликацијата или услугата да пристапува до системските камери за да фотографира и да снима видеа"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Оваа привилегирана или системска апликација може да фотографира и да снима видеа со системската камера во секое време. Потребно е апликацијата да ја има и дозволата android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволете апликацијатa или услугата да прима повратни повици за отворањето или затворањето на уредите со камера."</string>
@@ -988,7 +998,7 @@
<string name="searchview_description_search" msgid="1045552007537359343">"Пребарај"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"Пребарај барање"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"Исчисти барање"</string>
- <string name="searchview_description_submit" msgid="6771060386117334686">"Поднеси барање"</string>
+ <string name="searchview_description_submit" msgid="6771060386117334686">"Испрати барање"</string>
<string name="searchview_description_voice" msgid="42360159504884679">"Гласовно пребарување"</string>
<string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Овозможи „Истражувај со допир“?"</string>
<string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со таблетот."</string>
@@ -1439,7 +1449,7 @@
<string name="upload_file" msgid="8651942222301634271">"Избери датотека"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"Не е избрана датотека"</string>
<string name="reset" msgid="3865826612628171429">"Ресетирај"</string>
- <string name="submit" msgid="862795280643405865">"Поднеси"</string>
+ <string name="submit" msgid="862795280643405865">"Испрати"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликацијата за возење работи"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Допрете за да излезете од апликацијата за возење."</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да го зголемиме звукот над препорачаното ниво?\n\nСлушањето звуци со голема јачина подолги периоди може да ви го оштети сетилото за слух."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Да се користи кратенка за „Пристапност“?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција за пристапност."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Да се вклучи кратенка за функциите за пристапност?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучат функциите за пристапност. Ова може да го промени начинот на функционирање на уредот.\n\nТековни функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМоже да ги промените избраните функции во „Поставки > Пристапност“."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Да се вклучи кратенка за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучи функцијата за пристапност <xliff:g id="SERVICE">%1$s</xliff:g>. Ова може да го промени начинот на функционирање на уредот.\n\nМоже да ја измените кратенкава да биде за друга функција во „Поставки > Пристапност“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Вклучи"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Не вклучувај"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 8ec1c68..ce346c9 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ഈ ആപ്പിന് ഏത് സമയത്തും മൈക്രോഫോൺ ഉപയോഗിച്ചുകൊണ്ട് ഓഡിയോ റെക്കോർഡുചെയ്യാൻ കഴിയും."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-ലേക്ക് കമാൻഡുകൾ അയയ്ക്കുക"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"സിമ്മിലേക്ക് കമാൻഡുകൾ അയയ്ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് വളരെ അപകടകരമാണ്."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ശാരീരിക പ്രവർത്തനം തിരിച്ചറിയുക"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"നിങ്ങളുടെ ശാരീരിക പ്രവർത്തനം ഈ ആപ്പിന് തിരിച്ചറിയാനാവും."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ചിത്രങ്ങളും വീഡിയോകളും എടുക്കുക"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ഏതുസമയത്തും ക്യാമറ ഉപയോഗിച്ചുകൊണ്ട് ചിത്രങ്ങൾ എടുക്കാനും വീഡിയോകൾ റെക്കോർഡുചെയ്യാനും ഈ ആപ്പിന് കഴിയും."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ, സിസ്റ്റം ക്യാമറ ആക്സസ് ചെയ്യുന്നതിന് ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"സിസ്റ്റം ക്യാമറ ഉപയോഗിച്ച് ഏത് സമയത്തും ചിത്രങ്ങളെടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ വിശേഷാധികാര അല്ലെങ്കിൽ സിസ്റ്റം ആപ്പിന് കഴിയും. ആപ്പിലും android.permission.CAMERA അനുമതി ഉണ്ടായിരിക്കണം"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ക്യാമറയുള്ള ഉപകരണങ്ങൾ ഓണാക്കുന്നതിനെയോ അടയ്ക്കുന്നതിനെയോ കുറിച്ചുള്ള കോൾബാക്കുകൾ സ്വീകരിക്കാൻ ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കണോ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"കുറുക്കുവഴി ഓണായിരിക്കുമ്പോൾ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ഉപയോഗസഹായി ഫീച്ചറുകൾക്കുള്ള കുറുക്കുവഴി ഓണാക്കണോ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത്, ഉപയോഗസഹായി ഫീച്ചറുകൾ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന രീതിയെ ഇത് മാറ്റിയേക്കാം.\n\nനിലവിലുള്ള ഫീച്ചറുകൾ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nതിരഞ്ഞെടുത്ത ഫീച്ചറുകൾ ക്രമീകരണം > ഉപയോഗസഹായി എന്നതിൽ മാറ്റാനാവും."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> കുറുക്കുവഴി ഓണാക്കണോ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത് ഉപയോഗസഹായി ഫീച്ചറായ <xliff:g id="SERVICE">%1$s</xliff:g> എന്നതിനെ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന വിധം ഇത് മാറ്റിയേക്കാം.\n\nക്രമീകരണം > ഉപയോഗസഹായി എന്നതിലെ മറ്റൊരു ഫീച്ചറിലേക്ക് നിങ്ങൾക്ക് ഈ കുറുക്കുവഴി മാറ്റാനാവും."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ഓണാക്കുക"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ഓണാക്കരുത്"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 6b7a365..313c406 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"Энэ апп ямар ч үед микрофон ашиглан аудио бичих боломжтой."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM картад тушаал илгээх"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Апп-д SIM рүү комманд илгээхийг зөвшөөрнө. Энэ маш аюултай."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"биеийн дасгал хөдөлгөөн таних"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Энэ апп таны биеийн дасгал хөдөлгөөнийг таних боломжтой."</string>
<string name="permlab_camera" msgid="6320282492904119413">"зураг авах болон видео бичих"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Энэ апп ямар ч үед камер ашиглан зураг авж, видео хийх боломжтой."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Видео болон зураг авахын тулд апп эсвэл үйлчилгээнд хандахыг системийн камерт зөвшөөрөх"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Энэ хамгаалагдсан эсвэл системийн апп нь системийн камер ашиглан ямар ч үед зураг авч, видео бичих боломжтой. Мөн түүнчлэн, апп нь android.permission.CAMERA-н зөвшөөрөлтэй байх шаардлагатай"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Аппликэйшн эсвэл үйлчилгээнд камерын төхөөрөмжүүдийг нээж эсвэл хааж байгаа тухай залгасан дуудлага хүлээн авахыг зөвшөөрөх."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Хандалтын онцлогуудын товчлолыг асаах уу?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарснаар хандалтын онцлогууд асна. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nОдоогийн онцлогууд:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТа сонгосон онцлогуудыг Тохиргоо > Хандалт хэсэгт өөрчлөх боломжтой."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>-н товчлолыг асаах уу?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарах нь хандалтын онцлог болох <xliff:g id="SERVICE">%1$s</xliff:g>-г асаадаг. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nТа Тохиргоо > Хандалт хэсэгт энэ товчлолыг өөр онцлогт оноож өөрчлөх боломжтой."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Асаах"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Бүү асаа"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4f8925c..effa6b6 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"हा अॅप कोणत्याही वेळी मायक्रोफोन वापरून ऑडिओ रेकॉर्ड करू शकता."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"सिम वर कमांड पाठवा"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"अॅप ला सिम वर कमांड पाठविण्याची अनुमती देते. हे खूप धोकादायक असते."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक ॲक्टिव्हिटी ओळखा"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"हे अॅप तुमच्या शारीरिक ॲक्टिव्हिटी ओळखू शकते."</string>
<string name="permlab_camera" msgid="6320282492904119413">"चित्रे आणि व्हिडिओ घ्या"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"हा अॅप कोणत्याही वेळी कॅमेरा वापरून चित्रेे घेऊ आणि व्हिडिओ रेकॉर्ड करू शकतो."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"फोटो आणि व्हिडिओ काढण्यासाठी ॲप्लिकेशन किंवा सेवेला सिस्टम कॅमेरे ॲक्सेस करण्याची अनुमती द्या"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"हे विशेषाधिकृत किंवा सिस्टम ॲप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपकडे android.permission.CAMERA परवानगी असण्याचीदेखील आवश्यकता आहे"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"एखाद्या अॅप्लिकेशन किंवा सेवेला कॅमेरा डिव्हाइस सुरू किंवा बंद केल्याची कॉलबॅक मिळवण्याची अनुमती द्या."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"शिफारस केलेल्या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्याने आपल्या श्रवणशक्तीची हानी होऊ शकते."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्हॉल्यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"अॅक्सेसिबिलिटी वैशिष्ट्यांसाठी शॉर्टकट सुरू करायचा आहे का?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्ये सुरू होतात. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nसध्याची वैशिष्ट्ये:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतुम्ही हा शॉर्टकट सेटिंग्ज > अॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट सुरू करायचा आहे का?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने <xliff:g id="SERVICE">%1$s</xliff:g>, एक अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होते. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nतुम्ही हा शॉर्टकट सेटिंग्ज > अॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"सुरू करा"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"सुरू करू नका"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 161be37..5849c36 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"tukar tetapan audio anda"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Membenarkan apl untuk mengubah suai tetapan audio global seperti kelantangan dan pembesar suara mana digunakan untuk output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"rakam audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Apl ini boleh merakam audio menggunakan mikrofon pada bila-bila masa."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"hantar perintah ke SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Membenarkan apl menghantar arahan kepada SIM. Ini amat berbahaya."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"camkan aktiviti fizikal"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Apl ini dapat mengecam aktiviti fizikal anda."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ambil gambar dan video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Apl ini boleh mengambil gambar dan merakam video menggunakan kamera pada bila-bila masa."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Benarkan aplikasi atau perkhidmatan mengakses kamera sistem untuk mengambil gambar dan video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Apl terlindung atau apl sistem ini boleh mengambil gambar dan merakam video menggunakan kamera sistem pada bila-bila masa. Apl juga perlu mempunyai kebenaran android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Benarkan aplikasi atau perkhidmatan menerima panggilan balik tentang peranti kamera yang dibuka atau ditutup."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Hidupkan pintasan untuk ciri kebolehaksesan?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan ciri kebolehaksesan. Hal ini mungkin mengubah cara peranti anda berfungsi.\n\nCiri semasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda boleh menukar ciri yang dipilih dalam Tetapan > Kebolehaksesan."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Hidupkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan <xliff:g id="SERVICE">%1$s</xliff:g>, iaitu satu ciri kebolehaksesan. Ini mungkin mengubah cara peranti anda berfungsi.\n\nAnda boleh menukar pintasan ini kepada ciri lain dalam Tetapan > Kebolehaksesan."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Hidupkan"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Jangan hidupkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index a21e4bc..be88208 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ဤအက်ပ်သည် မိုက်ခရိုဖုန်းကို အသုံးပြုပြီး အချိန်မရွေး အသံသွင်းနိုင်ပါသည်။"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM ထံသို့ ညွှန်ကြားချက်များကို ပို့ပါ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"အက်ပ်အား ဆင်းမ်ကဒ်ဆီသို့ အမိန့်များ ပေးပို့ခွင့် ပြုခြင်း။ ဤခွင့်ပြုမှုမှာ အန္တရာယ်အလွန် ရှိပါသည်။"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ကိုယ်လက်လှုပ်ရှားမှုကို မှတ်သားပါ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ဤအက်ပ်က သင်၏ကိုယ်လက်လှုပ်ရှားမှုကို မှတ်သားနိုင်ပါသည်။"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ဓါတ်ပုံနှင့်ဗွီဒီယိုရိုက်ခြင်း"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ဤအက်ပ်သည် ကင်မရာကို အသုံးပြု၍ ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်ပါသည်။"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ဓာတ်ပုံနှင့် ဗီဒီယိုများရိုက်ရန်အတွက် စနစ်ကင်မရာများကို အက်ပ် သို့မဟုတ် ဝန်ဆောင်မှုအား အသုံးပြုခွင့်ပေးခြင်း"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ဤခွင့်ပြုထားသည့် သို့မဟုတ် စနစ်အက်ပ်က စနစ်ကင်မရာအသုံးပြုပြီး ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်သည်။ အက်ပ်ကလည်း android.permission.CAMERA ခွင့်ပြုချက် ရှိရပါမည်"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ကင်မရာစက်များ ပွင့်နေခြင်း သို့မဟုတ် ပိတ်နေခြင်းနှင့် ပတ်သက်ပြီး ပြန်လည်ခေါ်ဆိုမှုများ ရယူရန် အပလီကေးရှင်း သို့မဟုတ် ဝန်ဆောင်မှုကို ခွင့်ပြုခြင်း။"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများအတွက် ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nလက်ရှိ ဝန်ဆောင်မှုများ-\n<xliff:g id="SERVICE">%1$s</xliff:g>\n\'ဆက်တင်များ > အများသုံးစွဲနိုင်မှု\' တွင် ရွေးထားသည့် ဝန်ဆောင်မှုများကို ပြောင်းနိုင်သည်။"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုဖြစ်သော <xliff:g id="SERVICE">%1$s</xliff:g> ကို ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nဤဖြတ်လမ်းလင့်ခ်ကို \'ဆက်တင်များ > အများသုံးစွဲနိုင်မှု\' တွင် နောက်ဝန်ဆောင်မှုတစ်ခုသို့ ပြောင်းနိုင်သည်။"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ဖွင့်ရန်"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"မဖွင့်ပါနှင့်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d25c3ca..a18df16 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"endre lydinnstillinger"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lar appen endre globale lydinnstillinger slik som volum og hvilken høyttaler som brukes for lydavspilling."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ta opp lyd"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Denne appen kan når som helst ta opp lyd med mikrofonen."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"sende kommandoer til SIM-kortet"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lar appen sende kommandoer til SIM-kortet. Dette er veldig farlig."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"gjenkjenn fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Denne appen kan gjenkjenne den fysiske aktiviteten din."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ta bilder og videoer"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Denne appen kan når som helst ta bilder og spille inn videoer ved hjelp av kameraet."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Gi en app eller tjeneste tilgang til systemkameraene for å ta bilder og spille inn videoer"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerte appen eller systemappen kan når som helst ta bilder og spille inn videoer med et systemkamera. Dette krever at appen også har tillatelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillat at en app eller tjeneste mottar tilbakekallinger om kameraenheter som åpnes eller lukkes."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du slå på snarveien for tilgjengelighetsfunksjoner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder inne volumtastene i noen sekunder, slås tilgjengelighetsfunksjoner på. Dette kan endre hvordan enheten din fungerer.\n\nNåværende funksjoner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan endre valgte funksjoner i Innstillinger > Tilgjengelighet."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du slå på <xliff:g id="SERVICE">%1$s</xliff:g>-snarveien?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder inne begge volumtastene i noen sekunder, slår du på <xliff:g id="SERVICE">%1$s</xliff:g>, en tilgjengelighetsfunksjon. Dette kan endre hvordan enheten din fungerer.\n\nDu kan endre denne snarveien til en annen funksjon i Innstillinger > Tilgjengelighet."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Slå på"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ikke slå på"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2fc711f..7b376ff 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"यस अनुप्रयोगले जुनसुकै समय माइक्रोफोनको प्रयोग गरी अडियो रेकर्ड गर्न सक्छ।"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM मा आदेशहरू पठाउन दिनुहोस्"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"फोटोहरू र भिडियोहरू लिनुहोस्।"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई फोटो र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"सर्वसुलभता कायम गर्ने सुविधाहरू प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"केही सेकेन्डसम्म दुवै भोल्युम बटन थिचिराख्नुभयो भने पहुँचसम्बन्धी सुविधाहरू सक्रिय हुन्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nहालका सुविधाहरू:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतपाईं सेटिङ > पहुँचमा गएर चयन गरिएका सुविधाहरू परिवर्तन गर्न सक्नुहुन्छ।"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"केही सेकेन्डसम्म दुवै भोल्युम बटन थिचिराख्नुले <xliff:g id="SERVICE">%1$s</xliff:g> नामक पहुँचसम्बन्धी सुविधा सक्रिय गर्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nतपाईं सेटिङ > पहुँचमा गई यो सर्टकटमार्फत अर्को सुविधा खुल्ने बनाउन सक्नुहुन्छ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"सक्रिय गरियोस्"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"सक्रिय नगरियोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 11a873a..d601905 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"je audio-instellingen wijzigen"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Hiermee kan de app algemene audio-instellingen wijzigen zoals het volume en welke luidspreker wordt gebruikt voor de uitvoer."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"audio opnemen"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Deze app kan op elk moment audio opnemen met de microfoon."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"opdrachten verzenden naar de simkaart"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Hiermee kan de app opdrachten verzenden naar de simkaart. Dit is erg gevaarlijk."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fysieke activiteit herkennen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Deze app kan je fysieke activiteit herkennen."</string>
<string name="permlab_camera" msgid="6320282492904119413">"foto\'s en video\'s maken"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Deze app kan op elk moment foto\'s maken en video\'s opnemen met de camera."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Een app of service toegang tot systeemcamera\'s geven om foto\'s en video\'s te maken"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Deze gemachtigde app of systeem-app kan op elk gewenst moment foto\'s maken en video\'s opnemen met een systeemcamera. De app moet ook het recht android.permission.CAMERA hebben."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Een app of service toestaan callbacks te ontvangen over camera-apparaten die worden geopend of gesloten."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Snelkoppeling voor toegankelijkheidsfuncties inschakelen?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, schakel je de toegankelijkheidsfuncties in. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nHuidige functies:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJe kunt de geselecteerde functies wijzigen via Instellingen > Toegankelijkheid."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Snelkoppeling voor <xliff:g id="SERVICE">%1$s</xliff:g> inschakelen?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, wordt de toegankelijkheidsfunctie <xliff:g id="SERVICE">%1$s</xliff:g> ingeschakeld. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nJe kunt deze sneltoets op een andere functie instellen via Instellingen > Toegankelijkheid."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Inschakelen"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Niet inschakelen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 188a9bc..f3a225a 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ଏହି ଆପ୍ ଯେକୌଣସି ସମୟରେ ମାଇକ୍ରୋଫୋନ୍ ବ୍ୟବହାର କରି ଅଡିଓ ରେକର୍ଡ କରିପାରିବ।"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMକୁ କମାଣ୍ଡ ପଠାନ୍ତୁ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIMକୁ କମାଣ୍ଡ ପଠାଇବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଏହା ବହୁତ ବିପଦପୂର୍ଣ୍ଣ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ଶାରୀରିକ ଗତିବିଧି ଚିହ୍ନଟକରେ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ଏହି ଆପ୍ଣ ଆପଣଙ୍କ ଶାରୀରିକ ଗତିବିଧିକୁ ଚିହ୍ନଟ କରିପାରେ"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକୁ ନିଅନ୍ତୁ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ଏହି ଆପ୍ ଯେକୌଣସି ସମୟରେ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଫଟୋ ଉଠାଇପାରେ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରେ।"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ଛବି ଏବଂ ଭିଡିଓଗୁଡ଼ିକୁ ନେବା ପାଇଁ ସିଷ୍ଟମ୍ କ୍ୟାମେରାଗୁଡ଼ିକୁ କୌଣସି ଆପ୍ଲିକେସନ୍ କିମ୍ବା ସେବା ଆକ୍ସେସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ବିଶେଷ ଅଧିକାର ଥିବା ଏହି ଆପ୍ କିମ୍ବା ସିଷ୍ଟମ୍ ଆପ୍ ଯେ କୌଣସି ସମୟରେ ଏକ ସିଷ୍ଟମ୍ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଛବି ଉଠାଇପାରିବ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରିବ। ଆପରେ ମଧ୍ୟ android.permission.CAMERA ଅନୁମତି ଆବଶ୍ୟକ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"କ୍ୟାମେରା ଡିଭାଇସଗୁଡ଼ିକ ଖୋଲିବା କିମ୍ବା ବନ୍ଦ କରିବା ବିଷୟରେ କଲବ୍ୟାକଗୁଡ଼ିକ ପାଇବାକୁ ଏକ ଆପ୍ଲିକେସନ୍ କିମ୍ବା ସେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରିବେ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ସର୍ଟକଟ୍ ଚାଲୁ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଏକ ଆକ୍ସେସବିଲିଟି ଫିଚର୍ ଆରମ୍ଭ ହେବ।"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ପାଇଁ ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nବର୍ତ୍ତମାନର ଫିଚରଗୁଡ଼ିକ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n ଆପଣ ସେଟିଂସ୍ &gt ଆକ୍ସେସିବିଲିଟୀରେ ଚୟନିତ ଫିଚରଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଏକ ଆକ୍ସେସିବିଲିଟୀ ଫିଚର୍ <xliff:g id="SERVICE">%1$s</xliff:g> ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nଆପଣ ସେଟିଂସ୍ &gt ଆକ୍ସେସିବିଲିଟୀରେ ଏହି ସର୍ଚକଟକୁ ଅନ୍ୟ ଏକ ଫିଚରରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ଚାଲୁ କରନ୍ତୁ ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 22d5f441..6ea5f52 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ਇਹ ਐਪ ਕਿਸੇ ਵੀ ਸਮੇਂ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਆਡੀਓ ਫ਼ਾਈਲ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ਸਰੀਰਕ ਸਰਗਰਮੀ ਨੂੰ ਪਛਾਣਨਾ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ਇਹ ਐਪ ਤੁਹਾਡੀ ਸਰੀਰਕ ਸਰਗਰਮੀ ਨੂੰ ਪਛਾਣ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਬਣਾਓ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ਇਹ ਐਪ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰੇ ਨੂੰ ਵਰਤ ਕੇ ਤਸਵੀਰਾਂ ਖਿੱਚ ਸਕਦੀ ਹੈ ਅਤੇ ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ਸਿਸਟਮ ਕੈਮਰੇ ਨੂੰ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਬਣਾਉਣ ਲਈ ਐਪਲੀਕੇਸ਼ਨ ਜਾਂ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ ਦਿਓ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ਇਹ ਵਿਸ਼ੇਸ਼ ਅਧਿਕ੍ਰਿਤ ਜਾਂ ਸਿਸਟਮ ਐਪ ਕਿਸੇ ਵੇਲੇ ਵੀ ਸਿਸਟਮ ਕੈਮਰੇ ਨੂੰ ਵਰਤ ਕੇ ਤਸਵੀਰਾਂ ਖਿੱਚ ਸਕਦੀ ਹੈ ਅਤੇ ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਨੂੰ ਵੀ android.permission.CAMERA ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਂ ਸੇਵਾ ਨੂੰ ਕੈਮਰਾ ਡੀਵਾਈਸਾਂ ਦੇ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕੀਤੇ ਜਾਣ ਬਾਰੇ ਕਾਲਬੈਕ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ।"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ਕੀ ਵੌਲਿਊਮ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣਾ ਹੈ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਲਈ ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ, ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਮੌਜੂਦਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਚੁਣੀਆਂ ਗਈਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ <xliff:g id="SERVICE">%1$s</xliff:g>, ਇੱਕ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਕਿਸੇ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ਚਾਲੂ ਕਰੋ"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ਚਾਲੂ ਨਾ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c9c3b46..ca8522b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -438,13 +438,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"zmienianie ustawień audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Pozwala aplikacji na modyfikowanie globalnych ustawień dźwięku, takich jak głośność oraz urządzenie wyjściowe."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nagrywanie dźwięku"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ta aplikacja może w dowolnym momencie nagrać dźwięk przez mikrofon."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"wysyłanie poleceń do karty SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Pozwala aplikacji na wysyłanie poleceń do karty SIM. To bardzo niebezpieczne."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznawanie aktywności fizycznej"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ta aplikacja może rozpoznawać Twoją aktywność fizyczną."</string>
<string name="permlab_camera" msgid="6320282492904119413">"wykonywanie zdjęć i filmów wideo"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ta aplikacja może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Zezwól na dostęp aplikacji lub usługi do aparatów systemu i robienie zdjęć oraz nagrywanie filmów"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta aplikacja systemowa z podwyższonymi uprawnieniami może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu systemowego. Wymaga przyznania uprawnień android.permission.CAMERA również aplikacji."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Zezwól na dostęp aplikacji lub usługi na otrzymywanie wywoływania zwrotnego o urządzeniach z aparatem, kiedy są one uruchamiane lub zamykane."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Włączyć skrót ułatwień dostępu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza ułatwienia dostępu. Może to zmienić sposób działania urządzenia.\n\nBieżące funkcje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\naby zmienić wybrane funkcje, kliknij Ustawienia > Ułatwienia dostępu."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Włączyć skrót <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza usługę <xliff:g id="SERVICE">%1$s</xliff:g>, stanowiącą ułatwienie dostępu. Może to zmienić sposób działania urządzenia.\n\nAby zmienić ten skrót i wskazać inną funkcję, kliknij Ustawienia > Ułatwienia dostępu."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Włącz"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nie włączaj"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 221e29c..450fddb 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas configurações de áudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Este app pode reconhecer sua atividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e gravar vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"Enquanto está sendo usado, este app pode tirar fotos e gravar vídeos usando a câmera."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tirar fotos e gravar vídeos em segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que um aplicativo ou serviço acesse as câmeras do sistema para tirar fotos e gravar vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
@@ -1622,12 +1626,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Não ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e908c7f..c318a24 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas definições de áudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que a app modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta app pode gravar áudio através do microfone em qualquer altura."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que a app envie comandos para o SIM. Esta ação é muito perigosa."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer a atividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta app consegue reconhecer a sua atividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Esta app pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que uma app ou um serviço aceda às câmaras do sistema para tirar fotos e vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app do sistema ou privilegiada pode tirar fotos e gravar vídeos através de uma câmara do sistema em qualquer altura. Também necessita da autorização android.permission.CAMERA para a app."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que uma app ou um serviço receba chamadas de retorno sobre dispositivos de câmara que estão a ser abertos ou fechados"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Pretende ativar o atalho das funcionalidades de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter premidas ambas as teclas de volume durante alguns segundos ativa as funcionalidades de acessibilidade. Estas podem alterar a forma como o seu dispositivo funciona.\n\nFuncionalidades atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\npode alterar as funcionalidades selecionadas em Definições > Acessibilidade."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Pretende ativar o atalho do serviço <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter premidas ambas as teclas de volume durante alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, uma funcionalidade de acessibilidade. Esta pode alterar a forma como o seu dispositivo funciona.\n\nPode alterar este atalho para outra funcionalidade em Definições > Acessibilidade."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Não ativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 221e29c..450fddb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -432,13 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas configurações de áudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Este app pode reconhecer sua atividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e gravar vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"Enquanto está sendo usado, este app pode tirar fotos e gravar vídeos usando a câmera."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tirar fotos e gravar vídeos em segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que um aplicativo ou serviço acesse as câmeras do sistema para tirar fotos e gravar vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
@@ -1622,12 +1626,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Não ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c2dea7e..0efa74a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -435,13 +435,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modificare setări audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"înregistreze sunet"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Această aplicație poate înregistra conținut audio folosind microfonul în orice moment."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"să trimită comenzi către SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recunoașterea activității fizice"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Această aplicație vă poate recunoaște activitatea fizică."</string>
<string name="permlab_camera" msgid="6320282492904119413">"realizarea de fotografii și videoclipuri"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Această aplicație poate să facă fotografii și să înregistreze videoclipuri folosind camera foto în orice moment."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permiteți unei aplicații sau unui serviciu accesul la camerele de sistem, ca să fotografieze și să înregistreze videoclipuri"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Această aplicație de sistem privilegiată poate să fotografieze și să înregistreze videoclipuri folosind o cameră de sistem în orice moment. Necesită și permisiunea android.permission.CAMERA pentru aplicație"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permiteți unei aplicații sau unui serviciu să primească apeluri inverse atunci când sunt deschise sau închise dispozitive cu cameră."</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activați comanda rapidă pentru funcțiile de accesibilitate?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Dacă apăsați ambele taste de volum câteva secunde, activați funcțiile de accesibilitate. Acest lucru poate schimba funcționarea dispozitivului.\n\nFuncțiile actuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuteți schimba funcțiile selectate din Setări > Accesibilitate."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activați comanda rapidă <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Dacă apăsați ambele taste de volum câteva secunde, activați funcția de accesibilitate <xliff:g id="SERVICE">%1$s</xliff:g>. Acest lucru poate schimba funcționarea dispozitivului.\n\nPuteți alege altă funcție pentru această comandă în Setări > Accesibilitate."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activați"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nu activați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f8d6dfb..d074960 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -438,13 +438,23 @@
<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="3976213377904701093">"Приложение может в любое время записывать аудио с помощью микрофона."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"Отправка команд SIM-карте"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Приложение сможет отправлять команды SIM-карте (данное разрешение представляет большую угрозу)."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"распознавать физическую активность"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Приложение может распознавать физическую активность."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Фото- и видеосъемка"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Приложение может в любое время делать фотографии и снимать видео с помощью камеры."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Доступ приложения или сервиса к системным настройкам камеры, позволяющим снимать фото и видео"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Это привилегированное или системное приложение может в любое время делать фотографии и записывать видео с помощью камеры. Для этого приложению также требуется разрешение android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешить приложению или сервису получать обратные вызовы при открытии и закрытии камер"</string>
@@ -1315,7 +1325,7 @@
<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_confirm_always_allow" msgid="2223014893129755950">"Всегда разрешать"</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">"SIM-карта удалена"</string>
<string name="sim_removed_message" msgid="9051174064474904617">"Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Использовать быстрое включение?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Использовать быстрое включение?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Чтобы включить специальные возможности, нажмите обе кнопки регулировки громкости и удерживайте несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nТекущие функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nЧтобы изменить выбранные функции, перейдите в настройки и нажмите \"Специальные возможности\"."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Использовать быстрое включение сервиса \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Чтобы включить функцию \"<xliff:g id="SERVICE">%1$s</xliff:g>\", нажмите обе кнопки регулировки громкости на несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nЧтобы назначить это сочетание клавиш другой функции, перейдите в настройки и выберите \"Специальные возможности\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включить"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Не включать"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 63615f7..6d88677 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"මෙම යෙදුමට ඕනෑම වේලාවක මයික්රෆෝනය භාවිතයෙන් ශ්රව්ය පටිගත කිරීමට හැකිය."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM වෙත විධාන යැවීම"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM වෙත විධාන ගෙන යාමට යෙදුමට අවසර දෙයි. මෙය ඉතා භයානක වේ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ශාරීරික ක්රියාකාරකම හඳුනා ගන්න"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"මෙම යෙදුමට ඔබේ ශාරීරික ක්රියාකාරකම හඳුනා ගැනීමට නොහැකිය"</string>
<string name="permlab_camera" msgid="6320282492904119413">"පින්තූර සහ වීඩියෝ ගන්න"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"මෙම යෙදුමට ඕනෑම වේලාවක කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"පින්තූර සහ වීඩියෝ ගැනීමට පද්ධති කැමරාවලට යෙදුමකට හෝ සේවාවකට ප්රවේශය ඉඩ දෙන්න"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"මෙම වරප්රසාද ලත් හෝ පද්ධති යෙදුමට ඕනෑම වේලාවක පද්ධති කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය. යෙදුම විසින් රඳවා තබා ගැනීමට android.permission.CAMERA ප්රවේශයද අවශ්ය වේ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"විවෘත වෙමින් හෝ වැසෙමින් පවතින කැමරා උපාංග පිළිබඳ පසු ඇමතුම් ලබා ගැනීමට යෙදුමකට හෝ සේවාවකට ඉඩ දෙන්න."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ප්රවේශ්යතා කෙටිමඟ භාවිතා කරන්නද?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"කෙටිමග ක්රියාත්මක විට, හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් තිස්සේ එබීමෙන් ප්රවේශ්යතා විශේෂාංගය ආරම්භ වනු ඇත."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ප්රවේශ්යතා විශේෂාංග සඳහා කෙටි මග ක්රියාත්මක කරන්නද?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්රවේශ්යතා විශේෂාංග ක්රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nවත්මන් විශේෂාංග:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nඔබට තේරූ විශේෂාංග සැකසීම් > ප්රවේශ්යතාව හි වෙනස් කළ හැකිය."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> කෙටි මග ක්රියාත්මක කරන්නද?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්රවේශ්යතා විශේෂාංගයක් වන <xliff:g id="SERVICE">%1$s</xliff:g> ක්රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nඔබට මෙම කෙටිමග සැකසීම් > ප්රවේශ්යතාව හි තවත් විශේෂාංගයකට වෙනස් කළ හැකිය."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ක්රියාත්මක කරන්න"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ක්රියාත්මක නොකරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4f0704b..5d7f8f6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -438,13 +438,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"meniť nastavenia zvuku"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nahrávať zvuk"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Táto aplikácia môže kedykoľvek nahrávať zvuk pomocou mikrofónu."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"posielanie príkazov do SIM karty"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikácii odosielať príkazy na SIM kartu. Toto je veľmi nebezpečné povolenie."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávanie fyzickej aktivity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Táto aplikácia dokáže rozpoznať vašu fyzickú aktivitu."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotiť a nakrúcať videá"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Táto aplikácia môže kedykoľvek fotografovať a zaznamenávať videá pomocou fotoaparátu."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Povoľte aplikácii alebo službe prístup k fotoaparátom systému na snímanie fotiek a videí"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Táto oprávnená alebo systémová aplikácia môže kedykoľvek fotiť a nahrávať videá fotoaparátom systému. Aplikácia musí mať tiež povolenie android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povoliť aplikácii alebo službe prijímať spätné volanie, keď sú zariadenia s kamerou otvorené alebo zatvorené."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Chcete zapnúť skratku pre funkcie dostupnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Pridržaním oboch tlačidiel hlasitosti na niekoľko sekúnd zapnete funkcie dostupnosti. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nAktuálne funkcie:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkcie môžete zmeniť v časti Nastavenia > Dostupnosť."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Chcete zapnúť skratku na službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Pridržaním oboch klávesov hlasitosti na niekoľko sekúnd zapnete funkciu dostupnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nTúto skratku môžete zmeniť na inú funkciu v časti Nastavenia > Dostupnosť."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnúť"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nezapínať"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 85f1124..7e6e300 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -438,13 +438,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"spreminjanje nastavitev zvoka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Aplikaciji omogoča spreminjanje splošnih zvočnih nastavitev, na primer glasnost in kateri zvočnik se uporablja."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snemanje zvoka"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ta aplikacija lahko poljubno uporablja mikrofon za snemanje zvoka."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"pošiljanje ukazov na kartico SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Aplikaciji dovoli pošiljanje ukazov kartici SIM. To je lahko zelo nevarno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje telesne dejavnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ta aplikacija lahko prepoznava vašo telesno dejavnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotografiranje in snemanje videoposnetkov"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ta aplikacija lahko poljubno uporablja fotoaparat za snemanje fotografij ali videoposnetkov."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Aplikaciji ali storitvi dovoli dostop do vgrajenih fotoaparatov za snemanje fotografij in videoposnetkov"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta prednostna ali sistemska aplikacija lahko z vgrajenim fotoaparatom kadar koli snema fotografije in videoposnetke. Aplikacija mora imeti omogočeno tudi dovoljenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Aplikaciji ali storitvi dovoli prejemanje povratnih klicev o odpiranju ali zapiranju naprav s fotoaparati."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite vklopiti bližnjico za funkcije za ljudi s posebnimi potrebami?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili funkcije za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nIzbrane funkcije lahko spremenite v meniju »Nastavitve« > »Funkcije za ljudi s posebnimi potrebami«."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite vklopiti bližnjico za <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili storitev <xliff:g id="SERVICE">%1$s</xliff:g>, ki je funkcija za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTo bližnjico lahko v meniju »Nastavitve« > »Funkcije za ljudi s posebnimi potrebami« spremenite, da bo uporabljena za drugo funkcijo."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vklopi"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ne vklopi"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 4fd25bd..f6ef6e9 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ndrysho cilësimet e audios"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lejon aplikacionin të modifikojë cilësimet globale të audios siç është volumi dhe se cili altoparlant përdoret për daljen."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"regjistro audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ky aplikacion mund të regjistrojë audio me mikrofonin në çdo kohë."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"dërgo komanda te karta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lejon aplikacionin t\'i dërgojë komanda kartës SIM. Kjo është shumë e rrezikshme."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"njih aktivitetin fizik"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ky aplikacion mund të njohë aktivitetin tënd fizik."</string>
<string name="permlab_camera" msgid="6320282492904119413">"bëj fotografi dhe video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ky aplikacion mund të nxjerrë fotografi dhe të regjistrojë video me kamerën tënde në çdo kohë."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Lejo një aplikacion ose shërbim të ketë qasje në kamerat e sistemit për të shkrepur fotografi dhe regjistruar video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ky aplikacion sistemi ose i privilegjuar mund të nxjerrë fotografi dhe të regjistrojë video duke përdorur një kamerë në çdo moment. Kërkon që autorizimi i android.permission.CAMERA të mbahet edhe nga aplikacioni"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lejo që një aplikacion ose shërbim të marrë telefonata mbrapsht për pajisjet e kamerës që hapen ose mbyllen."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Të aktivizohet shkurtorja për veçoritë e qasshmërisë?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon veçoritë e qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nVeçoritë aktuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nKe ndryshuar veçoritë e zgjedhura te Cilësimet > Qasshmëria."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Të aktivizohet shkurtorja për <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon <xliff:g id="SERVICE">%1$s</xliff:g>, një veçori të qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nMund të ndryshosh këtë shkurtore te një veçori tjetër te Cilësimet > Qasshmëria."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivizo"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Mos e aktivizo"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index aa37ea0..d799ae9 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -435,13 +435,23 @@
<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="3976213377904701093">"Ова апликација може да снима звук помоћу микрофона у било ком тренутку."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"слање команди на SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Омогућава апликацији да шаље команде SIM картици. То је веома опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавање физичких активности"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ова апликација може да препозна физичке активности."</string>
<string name="permlab_camera" msgid="6320282492904119413">"снимање фотографија и видео снимака"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ова апликација може да снима фотографије и видео снимке помоћу камере у било ком тренутку."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволите некој апликацији или услузи да приступа камерама система да би снимала слике и видео снимке"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ова привилегована системска апликација може да снима слике и видео снимке помоћу камере система у било ком тренутку. Апликација треба да има и дозволу android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволите апликацији или услузи да добија повратне позиве о отварању или затварању уређаја са камером."</string>
@@ -1644,12 +1654,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Желите ли да користите пречицу за приступачност?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Желите да укључите пречицу за функције приступачности?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако задржите оба тастера за јачину звука пар секунди, укључиће се функције приступачности. То може да промени начин рада уређаја.\n\nПостојеће функције:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените изабране функције у одељку Подешавања > Приступачност."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Желите да укључите пречицу за услугу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако задржите оба тастера за јачину звука пар секунди, укључује се <xliff:g id="SERVICE">%1$s</xliff:g>, функција приступачности. То може да промени начин рада уређаја.\n\nМожете да промените функцију на коју се односи ова пречица у одељку Подешавања > Приступачност."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Укључи"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Не укључуј"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index acea0d5..318f5a8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ändra dina ljudinställningar"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tillåter att appen ändrar globala ljudinställningar som volym och vilken högtalarutgång som används."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"spela in ljud"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Appen kan spela in ljud med mikrofonen när som helst."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"skicka kommandon till SIM-kortet"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillåter att appen skickar kommandon till SIM-kortet. Detta är mycket farligt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"känn igen fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Den här appen kan känna igen fysisk aktivitet."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ta bilder och spela in videoklipp"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Appen kan ta kort och spela in video med kameran när som helst."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ge en app eller tjänst behörighet att ta bilder och spela in videor med systemets kameror"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denna systemapp med särskild behörighet kan ta bilder och spela in videor med systemets kamera när som helst. Appen måste även ha behörigheten android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillåt att en app eller tjänst får återanrop när en kameraenhet öppnas eller stängs."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vill du aktivera genvägen till tillgänglighetsfunktioner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras tillgänglighetsfunktionerna. Det kan få enheten ett fungera annorlunda.\n\nAktuella funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ändra vilka funktioner som aktiveras under Inställningar > Tillgänglighet."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vill du aktivera genvägen till <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras <xliff:g id="SERVICE">%1$s</xliff:g>, en tillgänglighetsfunktion. Det kan leda till att enheten fungerar annorlunda.\n\nDu kan ändra vilken funktion som ska aktiveras med genvägen under Inställningar > Tillgänglighet."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivera"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Aktivera inte"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index aa0c520..a59499f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"badilisha mipangilio yako ya sauti"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Inaruhusu programu kurekebisha mipangilio ya sauti kila mahali kama vile sauti na ni kipaza sauti kipi ambacho kinatumika kwa kutoa."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"kurekodi sauti"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Programu hii inaweza kurekodi sauti kwa kutumia maikrofoni wakati wowote."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"tuma amri kwenye SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Huruhusu programu kutuma amri kwa SIM. Hii ni hatari sana."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"itambue shughuli unazofanya"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Programu hii inaweza kutambua shughuli unazofanya."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Kupiga picha na kurekodi video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Programu hii inaweza kupiga picha na kurekodi video kwa kutumia kamera wakati wowote."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ruhusu programu au huduma ifikie kamera za mfumo ili ipige picha na irekodi video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Programu hii ya mfumo au inayopendelewa inaweza kupiga picha na kurekodi video ikitumia kamera ya mfumo wakati wowote. Inahitaji ruhusa ya android.permission.CAMERA iwepo kwenye programu pia"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ruhusu programu au huduma ipokee simu zinazopigwa tena kuhusu vifaa vya kamera kufunguliwa au kufungwa."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa sekunde tatu itafungua kipengele cha ufikivu."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ungependa kuwasha njia ya mkato ya vipengele vya ufikivu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha vipengele vya ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nVipengele vya sasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUnaweza kubadilisha vipengele ulivyochagua katika Mipangilio > Ufikivu."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ungependa kuwasha njia ya mkato ya <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha <xliff:g id="SERVICE">%1$s</xliff:g>, kipengele cha ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nUnaweza kubadilisha njia hii ya mkato iwe kipengele kingine katika Mipangilio > Ufikivu."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Washa"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Usiwashe"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 068c375..49e6c7c 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்யலாம்."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"கட்டளைகளை சிம்மிற்கு அனுப்புதல்"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"சிம் க்குக் கட்டளைகளை அனுப்ப ஆப்ஸை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"உடல் செயல்பாட்டைக் கண்டறிதல்"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"உங்கள் உடல் செயல்பாட்டை இந்த ஆப்ஸால் கண்டறிய முடியும்."</string>
<string name="permlab_camera" msgid="6320282492904119413">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"படங்களையும் வீடியோக்களையும் எடுப்பதற்கு சிஸ்டம் கேமராக்களை அணுக ஆப்ஸையோ சேவையையோ அனுமதி"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"இந்த முன்னுரிமை பெற்ற அல்லது சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"கேமரா சாதனங்கள் திறக்கப்படும்போதோ மூடப்படும்போதோ அது குறித்த கால்பேக்குகளைப் பெற ஒரு ஆப்ஸையோ சேவையையோ அனுமதிக்கவும்."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"அணுகல்தன்மை அம்சங்களுக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருந்தால் அணுகல்தன்மை அம்சங்கள் ஆன் செய்யப்படும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nதற்போதைய அம்சங்கள்:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nதேர்ந்தெடுத்த அம்சங்களை அமைப்புகள் > அணுகல்தன்மைக்குச் சென்று உங்களால் மாற்ற முடியும்."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> அம்சத்துக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் அணுகல்தன்மை அம்சமான <xliff:g id="SERVICE">%1$s</xliff:g> ஆன் ஆகும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ஆன் செய்"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ஆன் செய்யாதே"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6016082..caaf8a9 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"ఈ యాప్ మైక్రోఫోన్ని ఉపయోగించి ఎప్పుడైనా ఆడియోను రికార్డ్ చేయగలదు."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMకి ఆదేశాలను పంపడం"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"సిమ్కు ఆదేశాలను పంపడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది చాలా ప్రమాదకరం."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"భౌతిక కార్యాకలాపాన్ని గుర్తించండి"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ఈ యాప్ మీ భౌతిక కార్యాకలాపాన్ని గుర్తించగలదు."</string>
<string name="permlab_camera" msgid="6320282492904119413">"చిత్రాలు మరియు వీడియోలు తీయడం"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"ఈ యాప్ కెమెరాను ఉపయోగించి ఎప్పుడైనా చిత్రాలను తీయగలదు మరియు వీడియోలను రికార్డ్ చేయగలదు."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ఫోటోలు, వీడియోలు తీయడానికి సిస్టమ్ కెమెరాలకు యాప్, లేదా సేవా యాక్సెస్ను అనుమతించండి"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ఈ విశేష లేదా సిస్టమ్ యాప్ ఎప్పుడైనా సిస్టమ్ కెమెరాను ఉపయోగించి ఫోటోలు తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు. యాప్కు android.permission.CAMERA అనుమతి ఇవ్వడం కూడా అవసరం"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"కెమెరా పరికరాలు తెరుచుకుంటున్నప్పుడు లేదా మూసుకుంటున్నప్పుడు కాల్బ్యాక్లను స్వీకరించడానికి యాప్ను లేదా సర్వీస్ను అనుమతించండి."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్కట్ను ఉపయోగించాలా?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"యాక్సెస్ సౌలభ్య ఫీచర్ల కోసం షార్ట్కట్ను ఆన్ చేయాలా?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"రెండు వాల్యూమ్ కీలను కొంత సేపు నొక్కి పట్టుకుంటే యాక్సెసిబిలిటీ ఫీచర్లు ఆన్ అవుతాయి. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nప్రస్తుత ఫీచర్లు:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nఎంపిక చేసిన ఫీచర్లను మీరు సెట్టింగ్లు>యాక్సెసిబిలిటీలో మార్చవచ్చు."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> షార్ట్కట్ను ఆన్ చేయాలా?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"రెండు వాల్యూమ్ కీలను కొన్ని సెకన్ల పాటు నొక్కి పట్టుకోవడం ద్వారా యాక్సెసిబిలిటీ అయిన <xliff:g id="SERVICE">%1$s</xliff:g> ఆన్ అవుతుంది. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nసెట్టింగ్లు > యాక్సెసిబిలిటీలో, వేరొక ఫీచర్ను ప్రారంభించేలా ఈ షార్ట్ కట్ను మీరు మార్చవచ్చు."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ఆన్ చేయి"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ఆన్ చేయకండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2feea14..8c1917f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"แอปนี้สามารถบันทึกเสียงด้วยไมโครโฟนได้ทุกเมื่อ"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"ส่งคำสั่งไปยังซิม"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"อนุญาตให้แอปส่งคำสั่งไปยัง SIM ซึ่งอันตรายมาก"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"จดจำกิจกรรมการเคลื่อนไหวร่างกาย"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"แอปนี้จดจำกิจกรรมการเคลื่อนไหวร่างกายของคุณได้"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ถ่ายภาพและวิดีโอ"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"แอปนี้สามารถถ่ายภาพและวิดีโอด้วยกล้องได้ทุกเมื่อ"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"อนุญาตให้แอปพลิเคชันหรือบริการเข้าถึงกล้องของระบบเพื่อถ่ายภาพและวิดีโอ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"แอปของระบบหรือที่ได้รับสิทธิ์นี้จะถ่ายภาพและบันทึกวิดีโอโดยใช้กล้องของระบบได้ทุกเมื่อ แอปต้องมีสิทธิ์ android.permission.CAMERA ด้วย"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"อนุญาตให้แอปพลิเคชันหรือบริการได้รับโค้ดเรียกกลับเมื่อมีการเปิดหรือปิดอุปกรณ์กล้อง"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ใช้ทางลัดการช่วยเหลือพิเศษไหม"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มนาน 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"เปิดใช้ทางลัดสำหรับฟีเจอร์การช่วยเหลือพิเศษใช่ไหม"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิดฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nฟีเจอร์ปัจจุบัน:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nคุณจะเปลี่ยนฟีเจอร์ที่เลือกไว้ได้ในการตั้งค่า > การช่วยเหลือพิเศษ"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"เปิดใช้ทางลัด <xliff:g id="SERVICE">%1$s</xliff:g> ใช่ไหม"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิด <xliff:g id="SERVICE">%1$s</xliff:g> ซึ่งเป็นฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nคุณแก้ไขทางลัดนี้ให้เปิดฟีเจอร์อื่นได้ในการตั้งค่า > การช่วยเหลือพิเศษ"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"เปิด"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ไม่ต้องเปิด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 41ea057..af0073b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"baguhin ang mga setting ng iyong audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Pinapayagan ang app na baguhin ang mga pandaigdigang setting ng audio gaya ng volume at kung aling speaker ang ginagamit para sa output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"mag-record ng audio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Makakapag-record ng audio ang app na ito gamit ang mikropono anumang oras."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"magpadala ng mga command sa SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Pinapahintulutang magpadala ang app ng mga command sa SIM. Napakapanganib nito."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"tukuyin ang pisikal na aktibidad"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Matutukoy ng app na ito ang iyong pisikal na aktibidad."</string>
<string name="permlab_camera" msgid="6320282492904119413">"kumuha ng mga larawan at video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Makakakuha ng mga larawan at makakapag-record ng mga video ang app na ito gamit ang camera anumang oras."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Bigyan ang isang application o serbisyo ng access sa mga camera ng system para kumuha ng mga larawan at video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ang may pribilehiyong app o system app na ito ay makakakuha ng mga larawan at makakapag-record ng mga video gamit ang isang camera ng system anumang oras. Kinakailangang may android.permission.CAMERA na pahintulot din ang app"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Payagan ang isang application o serbisyo na makatanggap ng mga callback tungkol sa pagbubukas o pagsasara ng mga camera device."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Accessibility?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"I-on ang shortcut para sa mga feature ng pagiging naa-access?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mao-on ang mga feature ng accessibility kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nMga kasalukuyang feature:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuwede mong baguhin ang mga napiling feature sa Mga Setting > Accessibility."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"I-on ang shortcut ng <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mao-on ang feature ng accessibility na <xliff:g id="SERVICE">%1$s</xliff:g> kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nPuwede mong palitan ng ibang feature ang shortcut na ito sa Mga Setting > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"I-on"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Huwag i-on"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4513eb6..c0b2831 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ses ayarlarınızı değiştirin"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Uygulamaya ses düzeyi ve ses çıkışı için kullanılan hoparlör gibi genel ses ayarlarını değiştirme izni verir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ses kaydet"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Bu uygulama, istediği zaman mikrofonu kullanarak ses kaydedebilir."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM karta komut gönderme"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Uygulamanın SIM karta komut göndermesine izin verir. Bu izin çok tehlikelidir."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziksel aktiviteyi algıla"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu uygulama fiziksel aktivitenizi algılayabilir."</string>
<string name="permlab_camera" msgid="6320282492904119413">"resim çekme ve görüntü kaydetme"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Bu uygulama, herhangi bir zamanda kamerayı kullanarak fotoğraf ve video çekebilir."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Bir uygulama veya hizmetin fotoğraf ve video çekmek için sistem kameralarına erişmesine izin verin"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ayrıcalık tanınmış bu veya sistem uygulaması herhangi bir zamanda sistem kamerası kullanarak fotoğraf çekebilir ve video kaydedebilir. Uygulamanın da bu ayrıcalığa sahip olması için android.permission.CAMERA izni gerektirir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Bir uygulama veya hizmetin açılıp kapatılan kamera cihazları hakkında geri çağırmalar almasına izin verin."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kısayol açıkken ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erişilebilirlik özellikleri için kısayol açılsın mı?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak, erişilebilirlik özelliklerini açar. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nGeçerli özellikler:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nSeçilen özellikleri Ayarlar > Erişilebilirlik\'te değiştirebilirsiniz."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> kısayolu açılsın mı?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak <xliff:g id="SERVICE">%1$s</xliff:g> erişilebilirlik özelliğini etkinleştirir. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nBu kısayolu, Ayarlar > Erişilebilirlik\'te başka bir özellikle değiştirebilirsiniz."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Etkinleştir"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Etkinleştirme"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 0f5ce7e..4c5e13f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -438,13 +438,23 @@
<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="3976213377904701093">"Цей додаток може будь-коли записувати звук за допомогою мікрофона."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"надсилати команди на SIM-карту"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Дозволяє програмі надсилати команди на SIM-карту. Це дуже небезпечно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"розпізнавати фізичну активність"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Цей додаток може розпізнавати фізичну активність."</string>
<string name="permlab_camera" msgid="6320282492904119413">"фотограф. та знімати відео"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Цей додаток може будь-коли робити фотографії та записувати відео за допомогою камери."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволити додатку або сервісу отримувати доступ до системних камер, робити фото й записувати відео"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Цей пріоритетний системний додаток може будь-коли робити фото й записувати відео, використовуючи камеру системи. Додатку потрібен дозвіл android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволити додатку або сервісу отримувати зворотні виклики щодо відкриття чи закриття камер."</string>
@@ -1666,12 +1676,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Використовувати швидке ввімкнення?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Якщо цей засіб увімкнено, ви можете активувати спеціальні можливості, утримуючи обидві кнопки гучності протягом трьох секунд."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Увімкнути засіб спеціальних можливостей?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, вмикаються спеціальні можливості. Це впливає на роботу пристрою.\n\nПоточні функції:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВибрані функції можна змінити в налаштуваннях у меню спеціальних можливостей."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Увімкнути засіб швидкого доступу до сервісу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, буде ввімкнено спеціальні можливості – <xliff:g id="SERVICE">%1$s</xliff:g>. Це може вплинути на роботу пристрою.\n\nДля цієї комбінації клавіш можна вибрати іншу функцію в меню \"Налаштування > Спеціальні можливості\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Увімкнути"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Не вмикати"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7720480..7809d5b 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"یہ ایپ کسی بھی وقت مائیکروفون استعمال کرتے ہوئے آڈیو ریکارڈ کر سکتی ہے۔"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM کو ہدایات بھیجیں"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ایپ کو SIM کو کمانڈز بھیجنے کی اجازت دیتا ہے۔ یہ بہت خطرناک ہے۔"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"جسمانی سرگرمی کی شناخت کریں"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"یہ ایپ آپ کی جسمانی سرگرمی کی شناخت کر سکتی ہے۔"</string>
<string name="permlab_camera" msgid="6320282492904119413">"تصاویر لیں اور ویڈیوز بنائیں"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"یہ ایپ کسی بھی وقت کیمرا استعمال کرتے ہوئے تصاویر لے سکتی ہے اور ویڈیوز ریکارڈ کر سکتی ہے۔"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"ایپلیکیشن یا سروس کو سسٹم کے کیمرے تک رسائی حاصل کرنے کی اجازت دیتا ہے تاکہ وہ تصاویر لیں اور ویڈیوز ریکارڈ کریں۔"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"یہ مراعات یافتہ یا سسٹم ایپ کسی بھی وقت ایک سسٹم کیمرا استعمال کرتے ہوئے تصاویر اور ویڈیوز ریکارڈ کر سکتی ہے۔ ایپ کے پاس android.permission.CAMERA کے ليے بھی اجازت ہونا ضروری ہے۔"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ایپلیکیشن یا سروس کو کیمرا کے آلات کے کُھلنے یا بند ہونے سے متعلق کال بیکس موصول کرنے کی اجازت دیں۔"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ایکسیسبیلٹی شارٹ کٹ استعمال کریں؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ایکسیسبیلٹی خصوصیات کے لیے شارٹ کٹ آن کریں؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"دونوں والیوم کی کلیدوں کو کچھ سیکنڈز تک دبائیں رکھنے سے ایکسیسبیلٹی خصوصیات آن ہو جاتی ہیں۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nموجودہ خصوصیات:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nآپ ترتیبات اور ایکسیسبیلٹی میں منتخب کردہ خصوصیات کو تبدیل کر سکتے ہیں۔"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> شارٹ کٹ آن کریں؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"والیوم کی دونوں کلیدوں کو کچھ سیکنڈز تک دبائے رکھنے سے <xliff:g id="SERVICE">%1$s</xliff:g> ایکسیسبیلٹی خصوصیت آن ہو جاتی ہے۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nآپ ترتیبات اور ایکسیسبیلٹی میں دیگر خصوصیت کے لیے اس شارٹ کٹ کو تبدیل کر سکتے ہیں۔"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"آن کریں"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"آن نہ کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 49caf1b..c8ba3c6 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"audio sozlamalaringizni o‘zgartirish"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ovoz yozib olish"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Bu ilova xohlagan vaqtda mikrofon yordami audio yozib olishi mumkin."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM kartaga buyruqlar yuborish"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Dasturga SIM kartaga buyruqlar jo‘natishga ruxsat beradi. Bu juda ham xavfli."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"jismoniy harakatni aniqlash"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu ilova jismoniy harakatlaringizni aniqlay oladi."</string>
<string name="permlab_camera" msgid="6320282492904119413">"rasm va videoga olish"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Bu ilova xohlagan vaqtda kamera orqali suratga olishi va video yozib olishi mumkin."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ilova yoki xizmatga tizim kamerasi orqali surat va videolar olishga ruxsat berish"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu imtiyozli yoki tizim ilovasi istalgan vaqtda tizim kamerasi orqali surat va videolar olishi mumkin. Ilovada android.permission.CAMERA ruxsati ham yoqilgan boʻlishi talab qilinadi"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ilova yoki xizmatga kamera qurilmalari ochilayotgani yoki yopilayotgani haqida qayta chaqiruvlar qabul qilishi uchun ruxsat berish."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala tovush tugmasini 3 soniya bosib turing."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Maxsus imkoniyatlar uchun tezkor tugma yoqilsinmi?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Maxsus imkoniyatlarni yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nJoriy funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nTanlangan funksiyalarni Sozlamalar ichidagi Maxsus imkoniyatlar ustiga bosib oʻzgartirishingiz mumkin."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> tezkor tugmasi yoqilsinmi?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> funksiyasini yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nBu tezkor tugmalarni boshqa funksiyaga Sozlamalar ichidagi Maxsus imkoniyatlar orqali tayinlash mumkin."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Yoqilsin"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Yoqilmasin"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3b65cc1..ea83fe8 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"thay đổi cài đặt âm thanh của bạn"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Cho phép ứng dụng sửa đổi cài đặt âm thanh chung chẳng hạn như âm lượng và loa nào được sử dụng cho thiết bị ra."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ghi âm"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Ứng dụng này có thể ghi âm bằng micrô bất kỳ lúc nào."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"gửi lệnh đến SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Cho phép ứng dụng gửi lệnh đến SIM. Việc này rất nguy hiểm."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"nhận dạng hoạt động thể chất"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ứng dụng này có thể nhận dạng hoạt động thể chất của bạn."</string>
<string name="permlab_camera" msgid="6320282492904119413">"chụp ảnh và quay video"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Ứng dụng này có thể chụp ảnh và quay video bằng máy ảnh bất cứ lúc nào."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Cho phép một ứng dụng hoặc dịch vụ truy cập vào máy ảnh hệ thống để chụp ảnh và quay video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ứng dụng hệ thống có đặc quyền này có thể dùng máy ảnh hệ thống để chụp ảnh và quay video bất cứ lúc nào. Ngoài ra, ứng dụng này cũng cần có quyền android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Cho phép một ứng dụng hoặc dịch vụ nhận lệnh gọi lại khi các thiết bị máy ảnh đang được mở/đóng."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Khi phím tắt này đang bật, thao tác nhấn cả hai nút âm lượng trong 3 giây sẽ mở tính năng hỗ trợ tiếp cận."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bật phím tắt cho các tính năng hỗ trợ tiếp cận?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật các tính năng hỗ trợ tiếp cận. Việc bật các tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nCác tính năng hiện tại:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nBạn có thể thay đổi những tính năng đã chọn trong phần Cài đặt > Hỗ trợ tiếp cận."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bật phím tắt cho <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật <xliff:g id="SERVICE">%1$s</xliff:g>, một tính năng hỗ trợ tiếp cận. Việc bật tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nBạn có thể chuyển phím tắt này thành một tính năng khác trong phần Cài đặt > Hỗ trợ tiếp cận."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bật"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Không bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 10472cb..7d3645b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"此应用可随时使用麦克风进行录音。"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"向 SIM 卡发送命令"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允许应用向SIM卡发送命令(此权限具有很高的危险性)。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"识别身体活动"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"此应用可以识别您的身体活动。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍摄照片和视频"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"此应用可随时使用相机拍摄照片和录制视频。"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"要拍照或录制视频,请允许应用或服务访问系统相机"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"这个具有特权的系统应用随时可以使用系统相机拍照及录制视频。另外,应用还需要获取 android.permission.CAMERA 权限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允许应用或服务接收与打开或关闭摄像头设备有关的回调。"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用无障碍快捷方式吗?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"启用这项快捷方式后,同时按下两个音量按钮 3 秒钟即可启动无障碍功能。"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要开启无障碍功能快捷方式吗?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同时按住两个音量键几秒钟,即可开启无障碍功能。这样做可能会改变您设备的工作方式。\n\n当前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可以在“设置”>“无障碍”中更改所选功能。"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要开启<xliff:g id="SERVICE">%1$s</xliff:g>快捷方式吗?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同时按住两个音量键几秒钟,即可开启<xliff:g id="SERVICE">%1$s</xliff:g>无障碍功能。这样做可能会改变您设备的工作方式。\n\n您可以在“设置”>“无障碍”中将此快捷方式更改为开启另一项功能。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"开启"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"不开启"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 455ae54..893f3e9 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"此應用程式可以隨時使用麥克風錄音。"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"發送指令至 SIM 卡"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這項操作具有高危險性。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"識別體能活動"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"此應用程式可識別您的體能活動。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍照和拍攝影片"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"此應用程式可以隨時使用相機拍照和攝錄。"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"允許應用程式或服務存取系統相機來拍照和攝錄"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個獲特別權限的系統應用程式可以在任何時候使用系統相機來拍照和攝錄。此外,應用程式亦需要 android.permission.CAMERA 權限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回電。"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙功能快速鍵嗎?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用快速鍵後,同時按住音量按鈕 3 秒便可啟用無障礙功能。"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能捷徑嗎?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按下兩個音量鍵幾秒,以開啟無障礙功能。這可能會變更裝置的運作。\n\n目前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可在「設定」>「無障礙功能」中變更所選功能。"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 捷徑嗎?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按下兩個音量鍵幾秒,以開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 無障礙功能。這可能會變更裝置的運作。\n\n您可在「設定」>「無障礙功能」中變更此快速鍵。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"不要開啟"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5971d97..f92cf4f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -432,13 +432,23 @@
<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="3976213377904701093">"這個應用程式隨時可使用麥克風錄音。"</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"傳送指令到 SIM 卡"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這麼做非常危險。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"辨識體能活動"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"這個應用程式可以辨識你從事的體能活動。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍攝相片和影片"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"這個應用程式隨時可使用相機拍照及錄影。"</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"如要拍照或錄影,請允許應用程式或服務存取系統攝影機"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個具有特殊權限的系統應用程式隨時可以使用系統攝影機拍照及錄影。此外,你也必須將 android.permission.CAMERA 權限授予這個應用程式"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回呼。"</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使你的聽力受損。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙捷徑嗎?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用捷徑功能,只要同時按下兩個音量按鈕 3 秒,就能啟動無障礙功能。"</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能快速鍵嗎?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按住音量調高鍵和調低鍵數秒,即可開啟無障礙功能。這麼做可能會改變裝置的運作方式。\n\n目前的功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n你可以在 [設定] > [無障礙設定] 中變更選取的功能。"</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」快速鍵嗎?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按住音量調高鍵和調低鍵數秒,即可開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」無障礙功能。這麼做可能會改變裝置的運作方式。\n\n你可以在 [設定] > [無障礙設定] 中變更這個快速鍵觸發的功能。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"不要開啟"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4a1033c..c43588b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -432,13 +432,23 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"shintsha izilungiselelo zakho zomsindo"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ivumela uhlelo lokusebenza ukushintsha izilungiselelo zomsindo we-global njengevolomu nokuthi isiphi isipika esisetshenziselwa okukhiphayo."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"qopha umsindo"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Lolu hlelo lokusebenza lungafunda umsindo lisebenzisa imakrofoni noma kunini."</string>
+ <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
+ <skip />
+ <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
+ <skip />
+ <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
+ <skip />
<string name="permlab_sim_communication" msgid="176788115994050692">"thumela imilayezo ku-SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ivumela uhlelo lokusebenza ukuthumela imiyalo ku-SIM. Lokhu kuyingozi kakhulu."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"bona umsebenzi"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Lolu hlelo lokusebenza lingabona umsebenzi wakho."</string>
<string name="permlab_camera" msgid="6320282492904119413">"thatha izithombe namavidiyo"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Lolu hlelo lokusebenza lungathatha izithombe futhi lirekhode amavidiyo lusebenzisa ikhamera noma kunini."</string>
+ <!-- no translation found for permdesc_camera (5240801376168647151) -->
+ <skip />
+ <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
+ <skip />
+ <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
+ <skip />
<string name="permlab_systemCamera" msgid="3642917457796210580">"Vumela uhlelo lokusebenza noma isevisi ukufinyelela kumakhamera wesistimu ukuze uthathe izithombe namavidiyo"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Lolu hlelo lokusebenza oluhle noma lwesistimu lingathatha izithombe futhi lirekhode amavidiyo lisebenzisa ikhamera yesistimu noma kunini. Idinga imvume ye-android.permission.CAMERA ukuthi iphathwe nawuhlelo lokusebenza"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Vumela uhlelo lokusebenza noma isevisi ukwamukela ukuphinda ufonelwe mayelana namadivayisi wekhamera avuliwe noma avaliwe."</string>
@@ -1622,12 +1632,10 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Uma isinqamuleli sivuliwe, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqalisa isici sokufinyelela."</string>
- <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
- <skip />
+ <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vula isinqamuleli sezici zokufinyeleleka?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula izici zokufinyelela. Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nIzici zamanje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUngashintsha izici ezikhethiwe Kuzilungiselelo > Ukufinyeleleka."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
- <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
- <skip />
+ <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vula isinqamuleli se-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula i-<xliff:g id="SERVICE">%1$s</xliff:g>, eyisici sokufinyelela Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nUngashintshela lesi sinqamuleli kwesinye isici Kuzilungiselelo > Ukufinyeleleka."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vula"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ungavuli"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 20ef017f..644ed3a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9180,21 +9180,32 @@
<attr name="fontVariationSettings" format="string" />
</declare-styleable>
- <!-- Attributes that are read when parsing a <fontfamily> tag. -->
+ <!-- Attributes that are read when parsing a <fontfamily> tag.
+ {@deprecated Use Jetpack Core library instead.}
+ -->
<declare-styleable name="FontFamily">
- <!-- The authority of the Font Provider to be used for the request. -->
+ <!-- The authority of the Font Provider to be used for the request.
+ {@deprecated Use app:fontProviderAuthority with Jetpack Core library instead for
+ consistent behavior across all devices.}
+ -->
<attr name="fontProviderAuthority" format="string" />
<!-- The package for the Font Provider to be used for the request. This is used to verify
- the identity of the provider. -->
+ the identity of the provider.
+ {@deprecated Use app:fontProviderPackage with Jetpack Core library instead.}
+ -->
<attr name="fontProviderPackage" format="string" />
<!-- The query to be sent over to the provider. Refer to your font provider's documentation
- on the format of this string. -->
+ on the format of this string.
+ {@deprecated Use app:fontProviderQuery with Jetpack Core library instead.}
+ -->
<attr name="fontProviderQuery" format="string" />
<!-- The sets of hashes for the certificates the provider should be signed with. This is
used to verify the identity of the provider, and is only required if the provider is not
part of the system image. This value may point to one list or a list of lists, where each
individual list represents one collection of signature hashes. Refer to your font provider's
- documentation for these values. -->
+ documentation for these values.
+ {@deprecated Use app:fontProviderCerts with Jetpack Core library instead.}
+ -->
<attr name="fontProviderCerts" format="reference" />
</declare-styleable>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1c71bae..96ebc12 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -344,6 +344,11 @@
the app is uninstalled.
-->
<flag name="immutablyRestricted" value="0x10" />
+ <!--
+ Modifier for permission restriction. This permission cannot
+ be exempted by the installer.
+ -->
+ <flag name="installerExemptIgnored" value="0x20" />
</attr>
<!-- Specified the name of a group that this permission is associated
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 89e348a..f55114c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -271,11 +271,6 @@
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>
- <!-- When true, Android uses the PAC implementation included in WebView to handle
- networks with PAC scripts.
- When false, Android's own implementation of libpac is used.-->
- <bool name ="config_useWebViewPacProcessor">true</bool>
-
<!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
Please don't copy them, copy anything else. -->
@@ -1583,6 +1578,16 @@
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
<integer name="config_timeZoneRulesCheckRetryCount">5</integer>
+ <!-- Whether to enable primary location time zone provider overlay which allows the primary
+ location time zone provider to be replaced by an app at run-time. When disabled, only the
+ config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
+ location time zone provider, otherwise any system package is eligible. Anyone who wants to
+ disable the overlay mechanism can set it to false. -->
+ <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
+ <!-- Package name providing the primary location time zone provider. Used only when
+ config_enablePrimaryLocationTimeZoneOverlay is false. -->
+ <string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
+
<!-- Whether to enable network location overlay which allows network location provider to be
replaced by an app at run-time. When disabled, only the
config_networkLocationProviderPackageName package will be searched for network location
@@ -1826,6 +1831,8 @@
<string name="config_systemGallery" translatable="false">com.android.gallery3d</string>
<!-- The name of the package that will hold the system cluster service role. -->
<string name="config_systemAutomotiveCluster" translatable="false"></string>
+ <!-- The name of the package that will hold the system video call role. -->
+ <string name="config_systemVideoCall" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1e2d554..fe17eca 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3071,6 +3071,8 @@
<public-group type="string" first-id="0x01040028">
<!-- @hide @SystemApi @TestApi -->
<public name="config_systemAutomotiveCluster" />
+ <!-- @hide @SystemApi @TestApi -->
+ <public name="config_systemVideoCall" />
</public-group>
<public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 25a9bbd..fc489b1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1166,7 +1166,12 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_recordAudio">record audio</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_recordAudio">This app can record audio using the microphone at any time.</string>
+ <string name="permdesc_recordAudio">This app can record audio using the microphone while the app is in use.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_recordBackgroundAudio">record audio in the background</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_recordBackgroundAudio">This app can record audio using the microphone at any time.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_sim_communication">send commands to the SIM</string>
@@ -1181,7 +1186,12 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_camera">take pictures and videos</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_camera">This app can take pictures and record videos using the camera at any time.</string>
+ <string name="permdesc_camera">This app can take pictures and record videos using the camera while the app is in use.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_backgroundCamera">take pictures and videos in the background</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_backgroundCamera">This app can take pictures and record videos using the camera at any time.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
<string name="permlab_systemCamera">Allow an application or service access to system cameras to take pictures and videos</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 996e1f9..3e59549 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -287,7 +287,6 @@
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_disableTransitionAnimation" />
<java-symbol type="bool" name="config_enableAutoPowerModes" />
- <java-symbol type="bool" name="config_useWebViewPacProcessor" />
<java-symbol type="integer" name="config_autoPowerModeThresholdAngle" />
<java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" />
<java-symbol type="bool" name="config_autoPowerModePreferWristTilt" />
@@ -2159,6 +2158,8 @@
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
+ <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
+ <java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
index 0d5025a..54a281f2 100644
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
@@ -238,7 +238,8 @@
.setSchema("schemaType1")
.setCreationTimestampMs(5L)
.setScore(1)
- .setTtlMs(1L);
+ .setTtlMs(1L)
+ .setNamespace("");
HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
propertyProtoMap.put("longKey1",
PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
new file mode 100644
index 0000000..01a25b2
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.time;
+
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TimeZoneCapabilitiesTest {
+
+ private static final UserHandle TEST_USER_HANDLE = UserHandle.of(12345);
+
+ @Test
+ public void testEquals() {
+ TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
+ TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder2.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder2.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder2.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+ }
+
+ @Test
+ public void testParcelable() {
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
+ assertRoundTripParcelable(builder.build());
+ }
+
+ @Test
+ public void testTryApplyConfigChanges_permitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED)
+ .build();
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertEquals(expected, capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
+ }
+
+ @Test
+ public void testTryApplyConfigChanges_notPermitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+ .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+ .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
+ .build();
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ assertNull(capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
+ }
+}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java
similarity index 81%
rename from core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
rename to core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java
index faf908d..3948eb8 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
+++ b/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.app.time;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
@@ -23,16 +23,20 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
+@RunWith(AndroidJUnit4.class)
+@SmallTest
public class TimeZoneConfigurationTest {
- private static final int ARBITRARY_USER_ID = 9876;
-
@Test
public void testBuilder_copyConstructor() {
TimeZoneConfiguration.Builder builder1 =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(true)
.setGeoDetectionEnabled(true);
TimeZoneConfiguration configuration1 = builder1.build();
@@ -45,27 +49,27 @@
@Test
public void testIntrospectionMethods() {
- TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build();
+ TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder().build();
assertFalse(empty.isComplete());
- assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
+ assertFalse(empty.hasIsAutoDetectionEnabled());
- TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(true)
.setGeoDetectionEnabled(true)
.build();
assertTrue(completeConfig.isComplete());
- assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
+ assertTrue(completeConfig.hasIsGeoDetectionEnabled());
}
@Test
public void testBuilder_mergeProperties() {
- TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(true)
.build();
{
TimeZoneConfiguration mergedEmptyAnd1 =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ new TimeZoneConfiguration.Builder()
.mergeProperties(configuration1)
.build();
assertEquals(configuration1, mergedEmptyAnd1);
@@ -73,7 +77,7 @@
{
TimeZoneConfiguration configuration2 =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(false)
.build();
@@ -90,22 +94,14 @@
@Test
public void testEquals() {
TimeZoneConfiguration.Builder builder1 =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
+ new TimeZoneConfiguration.Builder();
{
TimeZoneConfiguration one = builder1.build();
assertEquals(one, one);
}
- {
- TimeZoneConfiguration.Builder differentUserBuilder =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1);
- TimeZoneConfiguration one = builder1.build();
- TimeZoneConfiguration two = differentUserBuilder.build();
- assertNotEquals(one, two);
- }
-
TimeZoneConfiguration.Builder builder2 =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
+ new TimeZoneConfiguration.Builder();
{
TimeZoneConfiguration one = builder1.build();
TimeZoneConfiguration two = builder2.build();
@@ -159,7 +155,7 @@
@Test
public void testParcelable() {
TimeZoneConfiguration.Builder builder =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
+ new TimeZoneConfiguration.Builder();
assertRoundTripParcelable(builder.build());
builder.setAutoDetectionEnabled(true);
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
deleted file mode 100644
index db127c6..0000000
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
+++ /dev/null
@@ -1,186 +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.timezonedetector;
-
-import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-
-import org.junit.Test;
-
-public class TimeZoneCapabilitiesTest {
-
- private static final int ARBITRARY_USER_ID = 12345;
-
- @Test
- public void testEquals() {
- TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true)
- .build();
- TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(false)
- .setGeoDetectionEnabled(false)
- .build();
-
- TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder()
- .setConfiguration(configuration1)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder()
- .setConfiguration(configuration1)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertEquals(one, two);
- }
-
- builder2.setConfiguration(configuration2);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setConfiguration(configuration2);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertEquals(one, two);
- }
-
- builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertEquals(one, two);
- }
-
- builder2.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertEquals(one, two);
- }
-
- builder2.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
- {
- TimeZoneCapabilities one = builder1.build();
- TimeZoneCapabilities two = builder2.build();
- assertEquals(one, two);
- }
- }
-
- @Test
- public void testParcelable() {
- TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true)
- .build();
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
- .setConfiguration(configuration)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- assertRoundTripParcelable(builder.build());
-
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- assertRoundTripParcelable(builder.build());
-
- builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- assertRoundTripParcelable(builder.build());
-
- builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
- assertRoundTripParcelable(builder.build());
- }
-
- @Test
- public void testApplyUpdate_permitted() {
- TimeZoneConfiguration oldConfiguration =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true)
- .build();
- TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
- .setConfiguration(oldConfiguration)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
- .build();
- assertEquals(oldConfiguration, capabilities.getConfiguration());
-
- TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(false)
- .build();
-
- TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
- .setAutoDetectionEnabled(false)
- .build();
- assertEquals(expected, capabilities.applyUpdate(configChange));
- }
-
- @Test
- public void testApplyUpdate_notPermitted() {
- TimeZoneConfiguration oldConfiguration =
- new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true)
- .build();
- TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
- .setConfiguration(oldConfiguration)
- .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
- .build();
- assertEquals(oldConfiguration, capabilities.getConfiguration());
-
- TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionEnabled(false)
- .build();
-
- assertNull(capabilities.applyUpdate(configChange));
- }
-}
diff --git a/core/tests/coretests/src/android/os/FileBridgeTest.java b/core/tests/coretests/src/android/os/FileBridgeTest.java
index d4f6b1f..708bfa6 100644
--- a/core/tests/coretests/src/android/os/FileBridgeTest.java
+++ b/core/tests/coretests/src/android/os/FileBridgeTest.java
@@ -16,6 +16,9 @@
package android.os;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+
import android.os.FileBridge.FileBridgeOutputStream;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
@@ -25,7 +28,6 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Random;
@@ -33,7 +35,7 @@
public class FileBridgeTest extends AndroidTestCase {
private File file;
- private FileOutputStream fileOs;
+ private ParcelFileDescriptor outputFile;
private FileBridge bridge;
private FileBridgeOutputStream client;
@@ -44,17 +46,17 @@
file = getContext().getFileStreamPath("meow.dat");
file.delete();
- fileOs = new FileOutputStream(file);
+ outputFile = ParcelFileDescriptor.open(file, MODE_CREATE | MODE_READ_WRITE);
bridge = new FileBridge();
- bridge.setTargetFile(fileOs.getFD());
+ bridge.setTargetFile(outputFile);
bridge.start();
client = new FileBridgeOutputStream(bridge.getClientSocket());
}
@Override
protected void tearDown() throws Exception {
- fileOs.close();
+ outputFile.close();
file.delete();
}
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index b669cc6..a9cfd28 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -17,8 +17,10 @@
package com.android.internal.jank;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -45,6 +47,13 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
@SmallTest
public class InteractionJankMonitorTest {
private ViewAttachTestActivity mActivity;
@@ -138,4 +147,27 @@
verify(tracker).cancel();
}
+ @Test
+ public void testCujTypeEnumCorrectlyDefined() throws Exception {
+ List<Field> cujEnumFields =
+ Arrays.stream(InteractionJankMonitor.class.getDeclaredFields())
+ .filter(field -> field.getName().startsWith("CUJ_")
+ && Modifier.isStatic(field.getModifiers())
+ && field.getType() == int.class)
+ .collect(Collectors.toList());
+
+ HashSet<Integer> allValues = new HashSet<>();
+ for (Field field : cujEnumFields) {
+ int fieldValue = field.getInt(null);
+ assertWithMessage(
+ "Field %s must have a mapping to a value in CUJ_TO_STATSD_INTERACTION_TYPE",
+ field.getName())
+ .that(fieldValue < CUJ_TO_STATSD_INTERACTION_TYPE.length)
+ .isTrue();
+ assertWithMessage("All CujType values must be unique. Field %s repeats existing value.",
+ field.getName())
+ .that(allValues.add(fieldValue))
+ .isTrue();
+ }
+ }
}
diff --git a/data/etc/com.android.storagemanager.xml b/data/etc/com.android.storagemanager.xml
index e85a82c..a1635fe 100644
--- a/data/etc/com.android.storagemanager.xml
+++ b/data/etc/com.android.storagemanager.xml
@@ -22,5 +22,6 @@
<permission name="android.permission.PACKAGE_USAGE_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 10c2b09..977703d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -153,6 +153,7 @@
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" />
+ <assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="media" />
@@ -222,6 +223,15 @@
targetSdk="29">
<new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
</split-permission>
+ <split-permission name="android.permission.RECORD_AUDIO"
+ targetSdk="31">
+ <new-permission name="android.permission.RECORD_BACKGROUND_AUDIO" />
+ </split-permission>
+ <split-permission name="android.permission.CAMERA"
+ targetSdk="31">
+ <new-permission name="android.permission.BACKGROUND_CAMERA" />
+ </split-permission>
+
<!-- This is a list of all the libraries available for application
code to link against. -->
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2779a75..81da5c8 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -435,6 +435,8 @@
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<!-- Permissions required for CTS test - AdbManagerTest -->
<permission name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permissions required for CTS test - TimeManagerTest -->
+ <permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 9eaeed1..29c8de6 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -49,6 +49,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2062338592": {
+ "message": "Looking for task of %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
+ "-2054442123": {
+ "message": "Setting Intent of %s to %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-2049725903": {
"message": "Task back pressed on root taskId=%d",
"level": "VERBOSE",
@@ -103,6 +115,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
},
+ "-1977793524": {
+ "message": "moveStackToDisplay: moving stackId=%d to displayId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1976930686": {
"message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.",
"level": "WARN",
@@ -163,6 +181,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
+ "-1890326172": {
+ "message": "no-history finish of %s on new resume",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1884933373": {
"message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
"level": "INFO",
@@ -199,12 +223,24 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "-1861864501": {
+ "message": "resumeTopActivityLocked: Going to sleep and all paused",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1847087163": {
"message": "TRANSIT_TASK_OPEN_BEHIND, adding %s to mOpeningApps",
"level": "DEBUG",
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1844540996": {
+ "message": " Initial targets: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1838803135": {
"message": "Attempted to set windowing mode to a display that does not exist: %d",
"level": "WARN",
@@ -253,6 +289,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-1768090656": {
+ "message": "Re-launching after pause: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1750206390": {
"message": "Exception thrown when creating surface for client %s (%s). %s",
"level": "WARN",
@@ -289,6 +331,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1704402370": {
+ "message": "resetTaskIntendedTask: calling finishActivity on %s",
+ "level": "WARN",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+ },
"-1699018375": {
"message": "Adding activity %s to task %s callers: %s",
"level": "INFO",
@@ -301,6 +349,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1679411993": {
+ "message": "setVr2dDisplayId called for: %d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1670695197": {
"message": "Attempted to add presentation window to a non-suitable display. Aborting.",
"level": "WARN",
@@ -313,6 +367,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1655805455": {
+ "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "-1647332198": {
+ "message": "remove RecentTask %s when finishing user %d",
+ "level": "INFO",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RecentTasks.java"
+ },
"-1638958146": {
"message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
"level": "INFO",
@@ -331,6 +397,24 @@
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java"
},
+ "-1613096551": {
+ "message": "Top resumed state released %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
+ "-1607026519": {
+ "message": "Ready to stop: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
+ "-1601745126": {
+ "message": "Launch on display check: allow launch for owner of the display",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-1598452494": {
"message": "activityDestroyedLocked: r=%s",
"level": "DEBUG",
@@ -343,12 +427,42 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-1587921395": {
+ "message": " Top targets: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
+ "-1585311008": {
+ "message": "Bring to front target: %s from %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
+ "-1575977269": {
+ "message": "Skipping %s: mismatch root %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-1568331821": {
"message": "Enabling listeners",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-1567866547": {
+ "message": "Collecting in transition %d: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
+ "-1558137010": {
+ "message": "Config is relaunching invisible activity %s called by %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1554521902": {
"message": "showInsets(ime) was requested by different window: %s ",
"level": "WARN",
@@ -415,12 +529,30 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityStarter.java"
},
+ "-1492696222": {
+ "message": "App died during pause, not stopping: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "-1474292612": {
+ "message": "Could not find task for id: %d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1471946192": {
"message": "Marking app token %s with replacing child windows.",
"level": "DEBUG",
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1452274694": {
+ "message": " CAN PROMOTE: promoting to parent %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1443029505": {
"message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
"level": "INFO",
@@ -439,6 +571,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-1432963966": {
+ "message": "Moving to DESTROYING: %s (destroy requested)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1427184084": {
"message": "addWindow: New client %s: window=%s Callers=%s",
"level": "VERBOSE",
@@ -475,6 +613,18 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
},
+ "-1376035390": {
+ "message": "No task found",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
+ "-1375751630": {
+ "message": " --- Start combine pass ---",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1364754753": {
"message": "Task vanished taskId=%d",
"level": "VERBOSE",
@@ -511,12 +661,36 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-1305966693": {
+ "message": "Sending position change to %s, onTop: %b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-1305791032": {
+ "message": "Moving to STOPPED: %s (stop complete)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1305755880": {
"message": "Initial config: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-1304806505": {
+ "message": "Starting new activity %s in new task %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
+ "-1295684101": {
+ "message": "Launch on display check: no caller info, skip check",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-1292329638": {
"message": "Added starting %s: startingWindow=%s startingView=%s",
"level": "VERBOSE",
@@ -571,12 +745,30 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-1198579104": {
+ "message": "Pushing next activity %s out to target's task %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+ },
+ "-1193946201": {
+ "message": "Can't report activity position update - client not running, activityRecord=%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1176488860": {
"message": "SURFACE isSecure=%b: %s",
"level": "INFO",
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
+ "-1164930508": {
+ "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1156118957": {
"message": "Updated config=%s",
"level": "DEBUG",
@@ -601,6 +793,12 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1136139407": {
+ "message": "no-history finish of %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1130891072": {
"message": "Orientation continue waiting for draw in %s",
"level": "VERBOSE",
@@ -667,12 +865,24 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1084548141": {
+ "message": "Launch on display check: allow launch any on display",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-1076978367": {
"message": "thawRotation: mRotation=%d",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1066383762": {
+ "message": "Sleep still waiting to pause %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1060365734": {
"message": "Attempted to add QS dialog window with bad token %s. Aborting.",
"level": "WARN",
@@ -697,12 +907,30 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1022146708": {
+ "message": "Skipping %s: mismatch activity type",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
+ "-1016578046": {
+ "message": "Moving to %s Relaunching %s callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1009117329": {
"message": "isFetchingAppTransitionSpecs=true",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "-1003060523": {
+ "message": "Finish needs to pause: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-993378225": {
"message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
"level": "VERBOSE",
@@ -721,6 +949,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
+ "-937498525": {
+ "message": "Executing finish of failed to pause activity: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-930893991": {
"message": "Set sync ready, syncId=%d",
"level": "VERBOSE",
@@ -745,6 +979,18 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-926231510": {
+ "message": "State unchanged from:%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-917215012": {
+ "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
+ "level": "WARN",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-916108501": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -757,18 +1003,36 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-903853754": {
+ "message": "pauseBackStacks: stack=%s mResumedActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
"-883738232": {
"message": "Adding more than one toast window for UID at a time.",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-877494781": {
+ "message": "Start pushing activity %s out to bottom task %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+ },
"-874446906": {
"message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
"level": "INFO",
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-866966979": {
+ "message": "Moving to PAUSED: %s (starting in paused state)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-861859917": {
"message": "Attempted to add window to a display that does not exist: %d. Aborting.",
"level": "WARN",
@@ -787,6 +1051,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-855366859": {
+ "message": " merging children in from %s: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-853404763": {
"message": "\twallpaper=%s",
"level": "DEBUG",
@@ -805,6 +1075,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-814760297": {
+ "message": "Looking for task of %s in %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-809771899": {
"message": "findFocusedWindow: Reached focused app=%s",
"level": "VERBOSE",
@@ -835,6 +1111,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-775004869": {
+ "message": "Not a match: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-771177730": {
"message": "Removing focused app token:%s displayId=%d",
"level": "VERBOSE",
@@ -865,12 +1147,30 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-729530161": {
+ "message": "Moving to DESTROYED: %s (no app)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-716565534": {
"message": "moveActivityStackToFront: unfocusable activity=%s",
"level": "DEBUG",
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-705939410": {
+ "message": "Waiting for pause to complete...",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-703543418": {
+ "message": " check sibling %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-694710814": {
"message": "Pausing rotation during drag",
"level": "DEBUG",
@@ -883,6 +1183,12 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
},
+ "-672228342": {
+ "message": "resumeTopActivityLocked: Top activity resumed %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-668956537": {
"message": " THUMBNAIL %s: CREATE",
"level": "INFO",
@@ -901,6 +1207,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-650261962": {
+ "message": "Sleep needs to pause %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-639305784": {
"message": "Could not report config changes to the window token client.",
"level": "WARN",
@@ -925,12 +1237,30 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-622017164": {
+ "message": "Finish Transition: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
"-618015844": {
"message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b mOnlyCore=%b. %s",
"level": "INFO",
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-606328116": {
+ "message": "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "-596163537": {
+ "message": "Waiting for top state to be released by %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-593535526": {
"message": "Binding proc %s with config %s",
"level": "VERBOSE",
@@ -949,6 +1279,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-571686216": {
+ "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"-561092364": {
"message": "onPointerDownOutsideFocusLocked called on %s",
"level": "INFO",
@@ -979,12 +1315,36 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowAnimator.java"
},
+ "-533690126": {
+ "message": "resumeTopActivityLocked: Resumed %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "-532081937": {
+ "message": " Commit activity becoming invisible: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
+ "-527683022": {
+ "message": "resumeTopActivityLocked: Skip resume: some activity pausing.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-519504830": {
"message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "-509601642": {
+ "message": " checking %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-507657818": {
"message": "Window %s is already added",
"level": "WARN",
@@ -1027,6 +1387,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-446752714": {
+ "message": " SKIP: sibling contains top target %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-445944810": {
"message": "finish(%b): mCanceled=%b",
"level": "DEBUG",
@@ -1051,6 +1417,18 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-427457280": {
+ "message": "App died while pausing: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "-417514857": {
+ "message": "Key dispatch not paused for screen off",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-415865166": {
"message": "findFocusedWindow: Found new focus @ %s",
"level": "VERBOSE",
@@ -1069,6 +1447,18 @@
"group": "WM_DEBUG_CONTAINERS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-401029526": {
+ "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
+ "level": "WARN",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-399343789": {
+ "message": "Skipping %s: different user",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-395922585": {
"message": "InsetsSource setWin %s",
"level": "DEBUG",
@@ -1117,6 +1507,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "-332679827": {
+ "message": "resumeNextFocusableActivityWhenStackIsEmpty: %s, go home",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-324085783": {
"message": "SURFACE CROP %s: %s",
"level": "INFO",
@@ -1153,12 +1549,36 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-302335479": {
+ "message": " remove from topTargets %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
+ "-300896109": {
+ "message": "moveTaskToStack: moving task=%d to stackId=%d toTop=%b",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-279436615": {
+ "message": "Moving to PAUSING: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-272719931": {
"message": "startLockTaskModeLocked: %s",
"level": "WARN",
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-262984451": {
+ "message": "Relaunch failed %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-260960989": {
"message": "Removing and adding activity %s to stack at top callers=%s",
"level": "INFO",
@@ -1177,6 +1597,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-234244777": {
+ "message": "Activity config changed during resume: %s, new next: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-198463978": {
"message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
"level": "VERBOSE",
@@ -1201,6 +1627,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-172326720": {
+ "message": "Saving icicle of %s: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-168799453": {
"message": "Allowing features %d:0x%s",
"level": "WARN",
@@ -1219,6 +1651,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "-118786523": {
+ "message": "Resume failed; resetting state to %s: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-116086365": {
"message": "******************** ENABLING SCREEN!",
"level": "INFO",
@@ -1279,6 +1717,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
+ "-21399771": {
+ "message": "activity %s already destroying, skipping request with reason:%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-7343917": {
"message": "onAnimationFinished(): targetStack=%s targetActivity=%s mRestoreTargetBehindStack=%s",
"level": "DEBUG",
@@ -1339,6 +1783,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "51927339": {
+ "message": "Skipping %s: voice session",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"73987756": {
"message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
"level": "INFO",
@@ -1357,12 +1807,24 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "86989930": {
+ "message": "setTaskWindowingMode: moving task=%d to windowingMode=%d toTop=%b",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"91350919": {
"message": "Attempted to set IME flag to a display that does not exist: %d",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "94402792": {
+ "message": "Moving to RESUMED: %s (in existing)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"95216706": {
"message": "hideIme target: %s ",
"level": "DEBUG",
@@ -1441,18 +1903,36 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
},
+ "182319432": {
+ "message": " remove from targets %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"184362060": {
"message": "screenshotTask(%d): mCanceled=%b",
"level": "DEBUG",
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "184610856": {
+ "message": "Start calculating TransitionInfo based on participants: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"186668272": {
"message": "Now changing app %s",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "189628502": {
+ "message": "Moving to STOPPING: %s (stop requested)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"194124419": {
"message": "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d",
"level": "DEBUG",
@@ -1525,6 +2005,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "259206414": {
+ "message": "Creating Transition: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
"269576220": {
"message": "Resuming rotation after drag",
"level": "DEBUG",
@@ -1567,6 +2053,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "306524472": {
+ "message": "Stop failed; moving to STOPPED: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"309039362": {
"message": "SURFACE MATRIX [%f,%f,%f,%f]: %s",
"level": "INFO",
@@ -1639,6 +2131,12 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "397382873": {
+ "message": "Moving to PAUSED: %s %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"399841913": {
"message": "SURFACE RECOVER DESTROY: %s",
"level": "INFO",
@@ -1657,6 +2155,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "430260320": {
+ "message": " sibling is a top target with mode %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"435494046": {
"message": "Attempted to add window to a display for which the application does not have access: %d. Aborting.",
"level": "WARN",
@@ -1687,6 +2191,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "485170982": {
+ "message": "Not finishing noHistory %s on stop because we're just sleeping",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"487621047": {
"message": "DisplayArea vanished name=%s",
"level": "VERBOSE",
@@ -1711,6 +2221,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "528150092": {
+ "message": " keep as target %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"531242746": {
"message": " THUMBNAIL %s: CREATE",
"level": "INFO",
@@ -1747,6 +2263,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
+ "579298675": {
+ "message": "Moving to DESTROYED: %s (removed from history)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"585096182": {
"message": "SURFACE isColorSpaceAgnostic=%b: %s",
"level": "INFO",
@@ -1867,6 +2389,12 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "674932310": {
+ "message": "Setting Intent of %s to target %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"685047360": {
"message": "Resizing window %s",
"level": "VERBOSE",
@@ -1891,18 +2419,36 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "709500946": {
+ "message": "resumeTopActivityLocked: Skip resume: need to start pausing",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"715749922": {
"message": "Allowlisting %d:%s",
"level": "WARN",
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "726205185": {
+ "message": "Moving to DESTROYED: %s (destroy skipped)",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "744171317": {
+ "message": " SKIP: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"745391677": {
"message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
"level": "INFO",
@@ -1921,6 +2467,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskPositioner.java"
},
+ "793568608": {
+ "message": " SKIP: sibling is visible but not part of transition",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"794570322": {
"message": "Now closing app %s",
"level": "VERBOSE",
@@ -1957,12 +2509,24 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "849147756": {
+ "message": "Finish collecting in transition %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"853091290": {
"message": "Moved stack=%s behind stack=%s",
"level": "DEBUG",
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "864551564": {
+ "message": "Launch on display check: disallow activity embedding without permission.",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"869266572": {
"message": "Removing activity %s from stack, reason= %s callers=%s",
"level": "INFO",
@@ -1981,12 +2545,30 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "875196661": {
+ "message": "Skipping stack: (mismatch activity\/stack) %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+ },
"892244061": {
"message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
"level": "INFO",
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "895158150": {
+ "message": "allPausedActivitiesComplete: r=%s state=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
+ "897964776": {
+ "message": "Complete pause: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"898863925": {
"message": "Attempted to add QS dialog window with unknown token %s. Aborting.",
"level": "WARN",
@@ -2041,18 +2623,48 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "988389910": {
+ "message": "resumeTopActivityLocked: Pausing %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "996960396": {
+ "message": "Starting Transition %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"1000601037": {
"message": "SyncSet{%x:%d} Set ready",
"level": "VERBOSE",
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
},
+ "1001509841": {
+ "message": "Auto-PIP allowed, entering PIP mode directly: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1001904964": {
"message": "***** BOOT TIMEOUT: forcing display enabled",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1015542198": {
+ "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
+ "1023413388": {
+ "message": "Finish waiting for pause of: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1040675582": {
"message": "Can't report activity configuration update - client not running, activityRecord=%s",
"level": "WARN",
@@ -2065,6 +2677,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1047769218": {
+ "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1049367566": {
"message": "Sending to proc %s new config %s",
"level": "VERBOSE",
@@ -2077,6 +2695,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1068803972": {
+ "message": "Activity paused: token=%s, timeout=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1073230342": {
"message": "startAnimation",
"level": "DEBUG",
@@ -2095,18 +2719,36 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
+ "1098891625": {
+ "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"1112047265": {
"message": "finishDrawingWindow: %s mDrawState=%s",
"level": "DEBUG",
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1115248873": {
+ "message": "Calling onTransitionReady: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"1115417974": {
"message": "FORCED DISPLAY SIZE: %dx%d",
"level": "INFO",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1126328412": {
+ "message": "Scheduling idle now: forceIdle=%b immediate=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1140424002": {
"message": "Finished screen turning on...",
"level": "INFO",
@@ -2125,12 +2767,30 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "1186730970": {
+ "message": " no common mode yet, so set it",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
+ "1192413464": {
+ "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"1208313423": {
"message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1217926207": {
+ "message": "Activity not running, resuming next.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1219600119": {
"message": "addWindow: win=%s Callers=%s",
"level": "DEBUG",
@@ -2167,12 +2827,24 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1270792394": {
+ "message": "Resumed after relaunch %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1288731814": {
"message": "WindowState.hideLw: setting mFocusMayChange true",
"level": "INFO",
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1316533291": {
+ "message": "State movement: %s from:%s to:%s reason:%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1325649102": {
"message": "Bad requesting window %s",
"level": "WARN",
@@ -2215,6 +2887,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "1364126018": {
+ "message": "Resumed activity; dropping state of: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1364498663": {
"message": "notifyAppResumed: wasStopped=%b %s",
"level": "VERBOSE",
@@ -2293,6 +2971,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "1469310004": {
+ "message": " SKIP: common mode mismatch. was %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"1495525537": {
"message": "createWallpaperAnimations()",
"level": "DEBUG",
@@ -2359,6 +3043,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1557732761": {
+ "message": "For Intent %s bringing to top: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"1563755163": {
"message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
"level": "WARN",
@@ -2383,12 +3073,24 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/WindowContainer.java"
},
+ "1585450696": {
+ "message": "resumeTopActivityLocked: Restarting %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1589610525": {
"message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "1610646518": {
+ "message": "Enqueueing pending finish: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1628345525": {
"message": "Now opening app %s",
"level": "VERBOSE",
@@ -2449,6 +3151,18 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1696210756": {
+ "message": "Launch on display check: allow launch on public display",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
+ "1706082525": {
+ "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"1720229827": {
"message": "Creating animation bounds layer",
"level": "INFO",
@@ -2509,6 +3223,18 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1794249572": {
+ "message": "Requesting StartTransition: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/TransitionController.java"
+ },
+ "1804435108": {
+ "message": "allResumedActivitiesIdle: stack=%d %s not idle",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"1822843721": {
"message": "Aborted starting %s: startingData=%s",
"level": "VERBOSE",
@@ -2545,6 +3271,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1837992242": {
+ "message": "Executing finish of activity: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1853793312": {
"message": "Notify removed startingWindow %s",
"level": "VERBOSE",
@@ -2563,12 +3295,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1884961873": {
+ "message": "Sleep still need to stop %d activities",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1891501279": {
"message": "cancelAnimation(): reason=%s",
"level": "DEBUG",
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "1894239744": {
+ "message": "Enqueueing pending pause: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1903353011": {
"message": "notifyAppStopped: %s",
"level": "VERBOSE",
@@ -2599,6 +3343,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "1947936538": {
+ "message": "Found matching class!",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"1964565370": {
"message": "Starting remote animation",
"level": "INFO",
@@ -2677,12 +3427,24 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "2034714267": {
+ "message": "Launch on display check: allow launch for caller present on the display",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+ },
"2034780299": {
"message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
"level": "INFO",
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "2039056415": {
+ "message": "Found matching affinity candidate!",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"2045641491": {
"message": "Checking %d opening apps (frozen=%b timeout=%b)...",
"level": "VERBOSE",
@@ -2731,6 +3493,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "2117696413": {
+ "message": "moveTaskToFront: moving taskId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"2119122320": {
"message": "setInputMethodTarget %s",
"level": "INFO",
@@ -2814,18 +3582,27 @@
"WM_DEBUG_STARTING_WINDOW": {
"tag": "WindowManager"
},
+ "WM_DEBUG_STATES": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_SWITCH": {
"tag": "WindowManager"
},
"WM_DEBUG_SYNC_ENGINE": {
"tag": "WindowManager"
},
+ "WM_DEBUG_TASKS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
"WM_DEBUG_WINDOW_ORGANIZER": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WINDOW_TRANSITIONS": {
+ "tag": "WindowManager"
+ },
"WM_ERROR": {
"tag": "WindowManager"
},
diff --git a/data/keyboards/Vendor_2378_Product_1008.kl b/data/keyboards/Vendor_2378_Product_1008.kl
index 478da03..7b19469 100644
--- a/data/keyboards/Vendor_2378_Product_1008.kl
+++ b/data/keyboards/Vendor_2378_Product_1008.kl
@@ -14,6 +14,10 @@
# OnLive, Inc. OnLive Wireless Controller, USB adapter
+key 164 MEDIA_PLAY_PAUSE
+key 167 MEDIA_RECORD
+key 168 MEDIA_REWIND
+key 208 MEDIA_FAST_FORWARD
key 304 BUTTON_A
key 305 BUTTON_B
key 307 BUTTON_X
@@ -22,6 +26,7 @@
key 311 BUTTON_R1
key 315 BUTTON_START
key 314 BUTTON_SELECT
+key 316 BUTTON_MODE
key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl
index d9cd171..cb2b73a 100644
--- a/data/keyboards/Vendor_2378_Product_100a.kl
+++ b/data/keyboards/Vendor_2378_Product_100a.kl
@@ -14,6 +14,10 @@
# OnLive, Inc. OnLive Wireless Controller
+key 164 MEDIA_PLAY_PAUSE
+key 167 MEDIA_RECORD
+key 168 MEDIA_REWIND
+key 208 MEDIA_FAST_FORWARD
key 304 BUTTON_A
key 305 BUTTON_B
key 307 BUTTON_X
@@ -22,6 +26,7 @@
key 311 BUTTON_R1
key 315 BUTTON_START
key 314 BUTTON_SELECT
+key 316 BUTTON_MODE
key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
new file mode 100644
index 0000000..9c84f50
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
@@ -0,0 +1,125 @@
+/*
+ * 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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.bugpatterns.android.TargetSdkChecker.binaryTreeExact;
+import static com.google.errorprone.matchers.FieldMatchers.anyFieldInClass;
+import static com.google.errorprone.matchers.FieldMatchers.staticField;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.anything;
+import static com.google.errorprone.matchers.Matchers.kindIs;
+import static com.google.errorprone.matchers.Matchers.not;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.BinaryTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.Tree.Kind;
+
+/**
+ * Each SDK level often has dozens of different behavior changes, which can be
+ * difficult for large app developers to adjust to during preview or beta
+ * releases. For this reason, {@code android.app.compat.CompatChanges} was
+ * introduced as a new best-practice for adding behavior changes.
+ * <p>
+ * During a preview or beta release, developers can temporarily opt-out of each
+ * individual change to aid debugging. This opt-out is only available during
+ * preview of beta releases, and cannot be adjusted on finalized builds.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkCompatChange",
+ summary = "Verifies that behavior changes use the modern compatibility framework",
+ severity = WARNING)
+public final class CompatChangeChecker extends BugChecker implements BinaryTreeMatcher {
+ private static final Matcher<ExpressionTree> VERSION_CODE =
+ anyFieldInClass("android.os.Build.VERSION_CODES");
+
+ // Ship has already sailed on these SDK levels; not worth fixing
+ private static final Matcher<ExpressionTree> LEGACY_VERSION_CODE = anyOf(
+ staticField("android.os.Build.VERSION_CODES", "BASE"),
+ staticField("android.os.Build.VERSION_CODES", "BASE_1_1"),
+ staticField("android.os.Build.VERSION_CODES", "CUPCAKE"),
+ staticField("android.os.Build.VERSION_CODES", "DONUT"),
+ staticField("android.os.Build.VERSION_CODES", "ECLAIR"),
+ staticField("android.os.Build.VERSION_CODES", "ECLAIR_0_1"),
+ staticField("android.os.Build.VERSION_CODES", "ECLAIR_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "FROYO"),
+ staticField("android.os.Build.VERSION_CODES", "GINGERBREAD"),
+ staticField("android.os.Build.VERSION_CODES", "GINGERBREAD_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "HONEYCOMB"),
+ staticField("android.os.Build.VERSION_CODES", "HONEYCOMB_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "HONEYCOMB_MR2"),
+ staticField("android.os.Build.VERSION_CODES", "ICE_CREAM_SANDWICH"),
+ staticField("android.os.Build.VERSION_CODES", "ICE_CREAM_SANDWICH_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN"),
+ staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN_MR2"),
+ staticField("android.os.Build.VERSION_CODES", "KITKAT"),
+ staticField("android.os.Build.VERSION_CODES", "KITKAT_WATCH"),
+ staticField("android.os.Build.VERSION_CODES", "L"),
+ staticField("android.os.Build.VERSION_CODES", "LOLLIPOP"),
+ staticField("android.os.Build.VERSION_CODES", "LOLLIPOP_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "M"),
+ staticField("android.os.Build.VERSION_CODES", "N"),
+ staticField("android.os.Build.VERSION_CODES", "N_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "O"),
+ staticField("android.os.Build.VERSION_CODES", "O_MR1"),
+ staticField("android.os.Build.VERSION_CODES", "P"),
+ staticField("android.os.Build.VERSION_CODES", "Q"),
+ staticField("android.os.Build.VERSION_CODES", "R"));
+
+ private static final Matcher<ExpressionTree> R_VERSION_CODE =
+ staticField("android.os.Build.VERSION_CODES", "R");
+
+ private static final Matcher<ExpressionTree> CUR_DEVELOPMENT_VERSION_CODE =
+ staticField("android.os.Build.VERSION_CODES", "CUR_DEVELOPMENT");
+
+ private static final Matcher<ExpressionTree> MODERN_VERSION_CODE =
+ allOf(VERSION_CODE, not(LEGACY_VERSION_CODE), not(CUR_DEVELOPMENT_VERSION_CODE));
+
+ private static final Matcher<ExpressionTree> BOOLEAN_OPERATOR = anyOf(
+ kindIs(Kind.LESS_THAN), kindIs(Kind.LESS_THAN_EQUAL),
+ kindIs(Kind.GREATER_THAN), kindIs(Kind.GREATER_THAN_EQUAL),
+ kindIs(Kind.EQUAL_TO), kindIs(Kind.NOT_EQUAL_TO));
+
+ private static final Matcher<BinaryTree> INVALID = anyOf(
+ allOf(BOOLEAN_OPERATOR, binaryTreeExact(MODERN_VERSION_CODE, anything())),
+ allOf(BOOLEAN_OPERATOR, binaryTreeExact(anything(), MODERN_VERSION_CODE)),
+ allOf(kindIs(Kind.GREATER_THAN), binaryTreeExact(anything(), R_VERSION_CODE)),
+ allOf(kindIs(Kind.LESS_THAN), binaryTreeExact(R_VERSION_CODE, anything())));
+
+ @Override
+ public Description matchBinary(BinaryTree tree, VisitorState state) {
+ if (INVALID.matches(tree, state)) {
+ return buildDescription(tree)
+ .setMessage("Behavior changes should use CompatChanges.isChangeEnabled() "
+ + "instead of direct SDK checks to ease developer transitions; "
+ + "see go/compat-framework for more details")
+ .build();
+
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
index 4f1af3e..3a1bc1e 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
@@ -18,6 +18,7 @@
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.bugpatterns.android.UidChecker.getFlavor;
+import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.enclosingClass;
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
@@ -60,8 +61,13 @@
private static final Matcher<ExpressionTree> BINDER_CALL = methodInvocation(
instanceMethod().onDescendantOf("android.os.IInterface").withAnyName());
- private static final Matcher<ExpressionTree> GET_USER_ID_CALL = methodInvocation(
- instanceMethod().onDescendantOf("android.content.Context").named("getUserId"));
+ private static final Matcher<ExpressionTree> GET_USER_ID_CALL = methodInvocation(anyOf(
+ instanceMethod().onExactClass("android.app.admin.DevicePolicyManager")
+ .named("myUserId"),
+ instanceMethod().onExactClass("android.content.pm.ShortcutManager")
+ .named("injectMyUserId"),
+ instanceMethod().onDescendantOf("android.content.Context")
+ .named("getUserId")));
private static final Matcher<ExpressionTree> USER_ID_FIELD = new Matcher<ExpressionTree>() {
@Override
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
index 48123ab..130b256 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
@@ -17,11 +17,14 @@
package com.google.errorprone.bugpatterns.android;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.contains;
import static com.google.errorprone.matchers.Matchers.enclosingClass;
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.throwStatement;
import static com.google.errorprone.matchers.Matchers.variableType;
@@ -29,13 +32,17 @@
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
-import com.google.errorprone.bugpatterns.BugChecker.CatchTreeMatcher;
+import com.google.errorprone.bugpatterns.BugChecker.TryTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
+import com.google.errorprone.predicates.TypePredicate;
import com.sun.source.tree.CatchTree;
+import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
+import com.sun.source.tree.TryTree;
import com.sun.source.tree.VariableTree;
+import com.sun.tools.javac.code.Type;
import java.util.List;
@@ -54,9 +61,17 @@
name = "AndroidFrameworkRethrowFromSystem",
summary = "Verifies that system_server calls use rethrowFromSystemServer()",
severity = WARNING)
-public final class RethrowFromSystemChecker extends BugChecker implements CatchTreeMatcher {
+public final class RethrowFromSystemChecker extends BugChecker implements TryTreeMatcher {
private static final Matcher<Tree> INSIDE_MANAGER =
enclosingClass(hasAnnotation("android.annotation.SystemService"));
+
+ // Purposefully exclude telephony Binder interfaces, since we know they
+ // always run under the separate AID_RADIO
+ private static final Matcher<ExpressionTree> SYSTEM_BINDER_CALL = methodInvocation(allOf(
+ instanceMethod().onDescendantOf("android.os.IInterface").withAnyName(),
+ not(instanceMethod().onClass(inPackage("com.android.internal.telephony"))),
+ not(instanceMethod().onClass(inPackage("com.android.internal.telecom")))));
+
private static final Matcher<VariableTree> REMOTE_EXCEPTION = variableType(
isSameType("android.os.RemoteException"));
private static final Matcher<StatementTree> RETHROW_FROM_SYSTEM = throwStatement(
@@ -64,17 +79,33 @@
.named("rethrowFromSystemServer")));
@Override
- public Description matchCatch(CatchTree tree, VisitorState state) {
+ public Description matchTry(TryTree tree, VisitorState state) {
if (INSIDE_MANAGER.matches(tree, state)
- && REMOTE_EXCEPTION.matches(tree.getParameter(), state)) {
- final List<? extends StatementTree> statements = tree.getBlock().getStatements();
- if (statements.size() != 1 || !RETHROW_FROM_SYSTEM.matches(statements.get(0), state)) {
- return buildDescription(tree)
- .setMessage("Must contain single "
- + "'throw e.rethrowFromSystemServer()' statement")
- .build();
+ && contains(ExpressionTree.class, SYSTEM_BINDER_CALL)
+ .matches(tree.getBlock(), state)) {
+ for (CatchTree catchTree : tree.getCatches()) {
+ if (REMOTE_EXCEPTION.matches(catchTree.getParameter(), state)) {
+ final List<? extends StatementTree> statements = catchTree.getBlock()
+ .getStatements();
+ if (statements.size() != 1
+ || !RETHROW_FROM_SYSTEM.matches(statements.get(0), state)) {
+ return buildDescription(catchTree)
+ .setMessage("Must contain single "
+ + "'throw e.rethrowFromSystemServer()' statement")
+ .build();
+ }
+ }
}
}
return Description.NO_MATCH;
}
+
+ private static TypePredicate inPackage(final String filter) {
+ return new TypePredicate() {
+ @Override
+ public boolean apply(Type type, VisitorState state) {
+ return type.tsym.packge().fullname.toString().startsWith(filter);
+ }
+ };
+ }
}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
index 232cf3f..e1ebf42 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
@@ -89,7 +89,7 @@
return Description.NO_MATCH;
}
- private static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
+ static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
Matcher<ExpressionTree> right) {
return new Matcher<BinaryTree>() {
@Override
diff --git a/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
index 46f0fb2..08969d6 100644
--- a/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
+++ b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
@@ -36,7 +36,8 @@
return new FieldReferenceMatcher() {
@Override
boolean classIsAppropriate(ClassSymbol classSymbol) {
- return classSymbol.getQualifiedName().contentEquals(className);
+ return classSymbol != null
+ && classSymbol.getQualifiedName().contentEquals(className);
}
@Override
@@ -50,12 +51,14 @@
return new FieldReferenceMatcher() {
@Override
boolean classIsAppropriate(ClassSymbol classSymbol) {
- return classSymbol.getQualifiedName().contentEquals(className);
+ return classSymbol != null
+ && classSymbol.getQualifiedName().contentEquals(className);
}
@Override
boolean fieldSymbolIsAppropriate(Symbol symbol) {
- return symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+ return symbol != null
+ && symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
}
};
}
@@ -64,12 +67,14 @@
return new FieldReferenceMatcher() {
@Override
boolean classIsAppropriate(ClassSymbol classSymbol) {
- return classSymbol.getQualifiedName().contentEquals(className);
+ return classSymbol != null
+ && classSymbol.getQualifiedName().contentEquals(className);
}
@Override
boolean fieldSymbolIsAppropriate(Symbol symbol) {
- return !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+ return symbol != null
+ && !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
}
};
}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java
new file mode 100644
index 0000000..4625d43
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.google.errorprone.bugpatterns.android;
+
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CompatChangeCheckerTest {
+ private CompilationTestHelper compilationHelper;
+
+ @Before
+ public void setUp() {
+ compilationHelper = CompilationTestHelper.newInstance(
+ CompatChangeChecker.class, getClass());
+ }
+
+ @Test
+ public void testSimple() {
+ compilationHelper
+ .addSourceFile("/android/os/Build.java")
+ .addSourceLines("Example.java",
+ "import android.os.Build;",
+ "public class Example {",
+ " void test(int targetSdkVersion) {",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion < Build.VERSION_CODES.S) { }",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion <= Build.VERSION_CODES.S) { }",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion > Build.VERSION_CODES.S) { }",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion >= Build.VERSION_CODES.S) { }",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion == Build.VERSION_CODES.S) { }",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion != Build.VERSION_CODES.S) { }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testObscure() {
+ compilationHelper
+ .addSourceFile("/android/os/Build.java")
+ .addSourceLines("Example.java",
+ "import android.os.Build;",
+ "import static android.os.Build.VERSION_CODES.S;",
+ "public class Example {",
+ " void test(int targetSdkVersion) {",
+ " // BUG: Diagnostic contains:",
+ " boolean indirect = S >= targetSdkVersion;",
+ " // BUG: Diagnostic contains:",
+ " if (targetSdkVersion > Build.VERSION_CODES.R) { }",
+ " if (targetSdkVersion >= Build.VERSION_CODES.R) { }",
+ " if (targetSdkVersion < Build.VERSION_CODES.R) { }",
+ " if (targetSdkVersion <= Build.VERSION_CODES.R) { }",
+ " // BUG: Diagnostic contains:",
+ " if (Build.VERSION_CODES.R < targetSdkVersion) { }",
+ " if (Build.VERSION_CODES.R <= targetSdkVersion) { }",
+ " if (Build.VERSION_CODES.R > targetSdkVersion) { }",
+ " if (Build.VERSION_CODES.R >= targetSdkVersion) { }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testIgnored() {
+ compilationHelper
+ .addSourceFile("/android/os/Build.java")
+ .addSourceLines("Example.java",
+ "import android.os.Build;",
+ "public class Example {",
+ " void test(int targetSdkVersion) {",
+ " if (targetSdkVersion < Build.VERSION_CODES.DONUT) { }",
+ " String result = \"test\" + Build.VERSION_CODES.S;",
+ " if (targetSdkVersion != Build.VERSION_CODES.CUR_DEVELOPMENT) { }",
+ " }",
+ "}")
+ .doTest();
+ }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/ContextUserIdCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/ContextUserIdCheckerTest.java
index c0b8cd7..c877230 100644
--- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/ContextUserIdCheckerTest.java
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/ContextUserIdCheckerTest.java
@@ -92,4 +92,56 @@
"}")
.doTest();
}
+
+ @Test
+ public void testDevicePolicyManager() {
+ compilationHelper
+ .addSourceFile("/android/annotation/SystemService.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/foo/IFooService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/RemoteException.java")
+ .addSourceLines("DevicePolicyManager.java",
+ "package android.app.admin;",
+ "import android.annotation.SystemService;",
+ "import android.content.Context;",
+ "import android.foo.IFooService;",
+ "import android.os.UserHandle;",
+ "import android.os.RemoteException;",
+ "@SystemService(\"dp\") public class DevicePolicyManager {",
+ " IFooService mService;",
+ " int myUserId() { return 0; }",
+ " void bar() throws RemoteException {",
+ " mService.baz(null, myUserId());",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testShortcutManager() {
+ compilationHelper
+ .addSourceFile("/android/annotation/SystemService.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/foo/IFooService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/RemoteException.java")
+ .addSourceLines("ShortcutManager.java",
+ "package android.content.pm;",
+ "import android.annotation.SystemService;",
+ "import android.content.Context;",
+ "import android.foo.IFooService;",
+ "import android.os.UserHandle;",
+ "import android.os.RemoteException;",
+ "@SystemService(\"shortcut\") public class ShortcutManager {",
+ " IFooService mService;",
+ " int injectMyUserId() { return 0; }",
+ " void bar() throws RemoteException {",
+ " mService.baz(null, injectMyUserId());",
+ " }",
+ "}")
+ .doTest();
+ }
}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemCheckerTest.java
index 32efbf2..0943bd6 100644
--- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemCheckerTest.java
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemCheckerTest.java
@@ -105,4 +105,27 @@
"}")
.doTest();
}
+
+ @Test
+ public void testTelephony() {
+ compilationHelper
+ .addSourceFile("/android/annotation/SystemService.java")
+ .addSourceFile("/com/android/internal/telephony/ITelephony.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceFile("/android/os/RemoteException.java")
+ .addSourceLines("TelephonyManager.java",
+ "import android.annotation.SystemService;",
+ "import com.android.internal.telephony.ITelephony;",
+ "import android.os.RemoteException;",
+ "@SystemService(\"telephony\") public class TelephonyManager {",
+ " ITelephony mService;",
+ " void bar() {",
+ " try {",
+ " mService.bar();",
+ " } catch (RemoteException ignored) {",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
}
diff --git a/errorprone/tests/res/android/os/Build.java b/errorprone/tests/res/android/os/Build.java
index bbf7ef2..2d354e2 100644
--- a/errorprone/tests/res/android/os/Build.java
+++ b/errorprone/tests/res/android/os/Build.java
@@ -18,6 +18,9 @@
public class Build {
public static class VERSION_CODES {
+ public static final int CUR_DEVELOPMENT = 10000;
public static final int DONUT = 4;
+ public static final int R = 30;
+ public static final int S = CUR_DEVELOPMENT;
}
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl b/errorprone/tests/res/com/android/internal/telephony/ITelephony.java
similarity index 76%
copy from core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
copy to errorprone/tests/res/com/android/internal/telephony/ITelephony.java
index 62240ba..61c4dd5 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl
+++ b/errorprone/tests/res/com/android/internal/telephony/ITelephony.java
@@ -14,6 +14,10 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package com.android.internal.telephony;
-parcelable TimeZoneConfiguration;
+import android.os.RemoteException;
+
+public interface ITelephony extends android.os.IInterface {
+ public void bar() throws RemoteException;
+}
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 4cd55e8..4c0f890 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -26,17 +26,17 @@
// Note: This field is accessed by native code.
public long mNativeObject; // BLASTBufferQueue*
- private static native long nativeCreate(long surfaceControl, long width, long height,
- boolean tripleBufferingEnabled);
+ private static native long nativeCreate(String name, long surfaceControl, long width,
+ long height, boolean tripleBufferingEnabled);
private static native void nativeDestroy(long ptr);
private static native Surface nativeGetSurface(long ptr);
private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height);
/** Create a new connection with the surface flinger. */
- public BLASTBufferQueue(SurfaceControl sc, int width, int height,
+ public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
boolean tripleBufferingEnabled) {
- mNativeObject = nativeCreate(sc.mNativeObject, width, height, tripleBufferingEnabled);
+ mNativeObject = nativeCreate(name, sc.mNativeObject, width, height, tripleBufferingEnabled);
}
public void destroy() {
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index 163823f..f768bc7 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -52,6 +52,7 @@
public static final long FLAG_SURFACE_CANVAS = 1 << 2;
// An invalid vsync id to be used when FRAME_TIMELINE_VSYNC_ID is unknown
+ // Needs to be in sync with android::ISurfaceComposer::INVALID_VSYNC_ID in native code
public static final long INVALID_VSYNC_ID = -1;
@LongDef(flag = true, value = {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 964640b..28d7911 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -3111,7 +3111,7 @@
@CriticalNative
private static native boolean nGetFillPath(long paintPtr, long src, long dst);
@CriticalNative
- private static native void nSetShader(long paintPtr, long shader);
+ private static native long nSetShader(long paintPtr, long shader);
@CriticalNative
private static native long nSetColorFilter(long paintPtr, long filter);
@CriticalNative
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 2a52ce9..21b8fc6 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -516,7 +516,7 @@
mLocaleList = localeList;
synchronized (MAP_LOCK) {
- FONT_PTR_MAP.append(mNativePtr, new WeakReference<>(this));
+ FONT_PTR_MAP.append(nGetNativeFontPtr(mNativePtr), new WeakReference<>(this));
}
}
@@ -591,14 +591,14 @@
*
* @param glyphId a glyph ID
* @param paint a paint object used for resolving glyph style
- * @param rect a nullable destination object. If null is passed, this function just return the
- * horizontal advance. If non-null is passed, this function fills bounding box
- * information to this object.
+ * @param outBoundingBox a nullable destination object. If null is passed, this function just
+ * return the horizontal advance. If non-null is passed, this function
+ * fills bounding box information to this object.
* @return the amount of horizontal advance in pixels
*/
public float getGlyphBounds(@IntRange(from = 0) int glyphId, @NonNull Paint paint,
- @Nullable RectF rect) {
- return nGetGlyphBounds(mNativePtr, glyphId, paint.getNativeInstance(), rect);
+ @Nullable RectF outBoundingBox) {
+ return nGetGlyphBounds(mNativePtr, glyphId, paint.getNativeInstance(), outBoundingBox);
}
/**
@@ -607,15 +607,15 @@
* Note that {@link android.graphics.Typeface} in {@link android.graphics.Paint} is ignored.
*
* @param paint a paint object used for retrieving font metrics.
- * @param metrics a nullable destination object. If null is passed, this function only retrieve
- * recommended interline spacing. If non-null is passed, this function fills to
- * font metrics to it.
+ * @param outMetrics a nullable destination object. If null is passed, this function only
+ * retrieve recommended interline spacing. If non-null is passed, this function
+ * fills to font metrics to it.
*
* @see Paint#getFontMetrics()
* @see Paint#getFontMetricsInt()
*/
- public void getMetrics(@NonNull Paint paint, @Nullable Paint.FontMetrics metrics) {
- nGetFontMetrics(mNativePtr, paint.getNativeInstance(), metrics);
+ public void getMetrics(@NonNull Paint paint, @Nullable Paint.FontMetrics outMetrics) {
+ nGetFontMetrics(mNativePtr, paint.getNativeInstance(), outMetrics);
}
/** @hide */
@@ -716,4 +716,7 @@
@FastNative
private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
+
+ @CriticalNative
+ private static native long nGetNativeFontPtr(long ptr);
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 1591b06..0defbd6 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -23,7 +23,18 @@
filegroup {
name: "wm_shell-sources",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ path: "src",
+}
+
+// TODO(b/168581922) protologtool do not support kotlin(*.kt)
+filegroup {
+ name: "wm_shell-sources-kt",
+ srcs: [
+ "src/**/*.kt",
+ ],
path: "src",
}
@@ -97,15 +108,23 @@
name: "WindowManager-Shell",
srcs: [
":wm_shell_protolog_src",
+ // TODO(b/168581922) protologtool do not support kotlin(*.kt)
+ ":wm_shell-sources-kt",
"src/**/I*.aidl",
],
resource_dirs: [
"res",
],
static_libs: [
+ "androidx.dynamicanimation_dynamicanimation",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
"protolog-lib",
"WindowManager-Shell-proto",
"androidx.appcompat_appcompat",
],
+ kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
+
+ min_sdk_version: "26",
}
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dismiss_circle_background.xml b/libs/WindowManager/Shell/res/drawable/dismiss_circle_background.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/dismiss_circle_background.xml
rename to libs/WindowManager/Shell/res/drawable/dismiss_circle_background.xml
diff --git a/packages/SystemUI/res/drawable/ic_skip_next_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_skip_next_white.xml
rename to libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml
diff --git a/packages/SystemUI/res/drawable/ic_skip_previous_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_skip_previous_white.xml
rename to libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
index 72287c1..727ac34 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- Layout for {@link com.android.systemui.pip.tv.PipControlButtonView}. -->
+<!-- Layout for {@link com.android.wm.shell.pip.tv.PipControlButtonView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:id="@+id/button"
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
index 22e0452..d2f235e 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
@@ -14,17 +14,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- Layout for {@link com.android.systemui.pip.tv.PipControlsView}. -->
+<!-- Layout for {@link com.android.wm.shell.pip.tv.PipControlsView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <com.android.systemui.pip.tv.PipControlButtonView
+ <com.android.wm.shell.pip.tv.PipControlButtonView
android:id="@+id/full_button"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
android:src="@drawable/pip_ic_fullscreen_white"
android:text="@string/pip_fullscreen" />
- <com.android.systemui.pip.tv.PipControlButtonView
+ <com.android.wm.shell.pip.tv.PipControlButtonView
android:id="@+id/close_button"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
@@ -32,7 +32,7 @@
android:src="@drawable/pip_ic_close_white"
android:text="@string/pip_close" />
- <com.android.systemui.pip.tv.PipControlButtonView
+ <com.android.wm.shell.pip.tv.PipControlButtonView
android:id="@+id/play_pause_button"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
index e6cd112..452f2cd 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.pip.tv.PipControlButtonView
+<com.android.wm.shell.pip.tv.PipControlButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index a049787..d8474b8 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -15,15 +15,15 @@
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="horizontal"
- android:paddingTop="350dp"
- android:background="#CC000000"
- android:gravity="top|center_horizontal"
- android:clipChildren="false">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:paddingTop="350dp"
+ android:background="#CC000000"
+ android:gravity="top|center_horizontal"
+ android:clipChildren="false">
- <com.android.systemui.pip.tv.PipControlsView
+ <com.android.wm.shell.pip.tv.PipControlsView
android:id="@+id/pip_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index a13e98c..227eec2 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -1,12 +1,24 @@
{
"version": "1.0.0",
"messages": {
+ "-1534364071": {
+ "message": "onTransitionReady %s: %s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TRANSITIONS",
+ "at": "com\/android\/wm\/shell\/Transitions.java"
+ },
"-1501874464": {
"message": "Fullscreen Task Appeared: #%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
},
+ "-1480787369": {
+ "message": "Transition requested: type=%d %s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TRANSITIONS",
+ "at": "com\/android\/wm\/shell\/Transitions.java"
+ },
"-1340279385": {
"message": "Remove listener=%s",
"level": "VERBOSE",
@@ -31,6 +43,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "-191422040": {
+ "message": "Transition animations finished, notifying core %s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TRANSITIONS",
+ "at": "com\/android\/wm\/shell\/Transitions.java"
+ },
"157713005": {
"message": "Task info changed taskId=%d",
"level": "VERBOSE",
@@ -53,6 +71,9 @@
"groups": {
"WM_SHELL_TASK_ORG": {
"tag": "WindowManagerShell"
+ },
+ "WM_SHELL_TRANSITIONS": {
+ "tag": "WindowManagerShell"
}
}
}
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 63b0f6f..e99350b 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -32,4 +32,8 @@
<!-- Allow one handed to enable round corner -->
<bool name="config_one_handed_enable_round_corner">true</bool>
+
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP menu is shown in center. -->
+ <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7fb641a..a9917a6 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -57,6 +57,9 @@
<dimen name="pip_resize_handle_margin">4dp</dimen>
<dimen name="pip_resize_handle_padding">0dp</dimen>
+ <dimen name="dismiss_target_x_size">24dp</dimen>
+ <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
+
<!-- How high we lift the divider when touching -->
<dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
index b275331..9d6271b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -50,9 +50,13 @@
// properties in a bad state).
t.setPosition(leash, 0, 0);
t.setWindowCrop(leash, null);
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
+ // TODO(shell-transitions): Eventually set everything in transition so there's no
+ // SF Transaction here.
+ if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ t.show(leash);
+ }
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index d650a95..8f496d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -28,7 +28,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.ArrayList;
@@ -59,16 +61,25 @@
// require us to report to both old and new listeners)
private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
- public ShellTaskOrganizer(SyncTransactionQueue syncQueue) {
+ // TODO(shell-transitions): move to a more "global" Shell location as this isn't only for Tasks
+ private final Transitions mTransitions;
+
+ public ShellTaskOrganizer(SyncTransactionQueue syncQueue, TransactionPool transactionPool,
+ ShellExecutor mainExecutor, ShellExecutor animExecutor) {
super();
addListener(new FullscreenTaskListener(syncQueue), WINDOWING_MODE_FULLSCREEN);
+ mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
@VisibleForTesting
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController,
- SyncTransactionQueue syncQueue) {
+ SyncTransactionQueue syncQueue, TransactionPool transactionPool,
+ ShellExecutor mainExecutor, ShellExecutor animExecutor) {
super(taskOrganizerController);
addListener(new FullscreenTaskListener(syncQueue), WINDOWING_MODE_FULLSCREEN);
+ mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
new file mode 100644
index 0000000..36e49d9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
@@ -0,0 +1,181 @@
+/*
+ * 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.wm.shell;
+
+import static android.window.TransitionInfo.TRANSIT_CLOSE;
+import static android.window.TransitionInfo.TRANSIT_HIDE;
+import static android.window.TransitionInfo.TRANSIT_OPEN;
+import static android.window.TransitionInfo.TRANSIT_SHOW;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.SystemProperties;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.ITransitionPlayer;
+import android.window.TransitionInfo;
+import android.window.WindowOrganizer;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.util.ArrayList;
+
+/** Plays transition animations */
+public class Transitions extends ITransitionPlayer.Stub {
+ private static final String TAG = "ShellTransitions";
+
+ /** Set to {@code true} to enable shell transitions. */
+ public static final boolean ENABLE_SHELL_TRANSITIONS =
+ SystemProperties.getBoolean("persist.debug.shell_transit", false);
+
+ private final WindowOrganizer mOrganizer;
+ private final TransactionPool mTransactionPool;
+ private final ShellExecutor mMainExecutor;
+ private final ShellExecutor mAnimExecutor;
+
+ /** Keeps track of currently tracked transitions and all the animations associated with each */
+ private final ArrayMap<IBinder, ArrayList<Animator>> mActiveTransitions = new ArrayMap<>();
+
+ Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
+ @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
+ mOrganizer = organizer;
+ mTransactionPool = pool;
+ mMainExecutor = mainExecutor;
+ mAnimExecutor = animExecutor;
+ }
+
+ // TODO(shell-transitions): real animations
+ private void startExampleAnimation(@NonNull IBinder transition, @NonNull SurfaceControl leash,
+ boolean show) {
+ final float end = show ? 1.f : 0.f;
+ final float start = 1.f - end;
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ final ValueAnimator va = ValueAnimator.ofFloat(start, end);
+ va.setDuration(500);
+ va.addUpdateListener(animation -> {
+ float fraction = animation.getAnimatedFraction();
+ transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
+ transaction.apply();
+ });
+ final Runnable finisher = () -> {
+ transaction.setAlpha(leash, end);
+ transaction.apply();
+ mTransactionPool.release(transaction);
+ mMainExecutor.execute(() -> {
+ mActiveTransitions.get(transition).remove(va);
+ onFinish(transition);
+ });
+ };
+ va.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finisher.run();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ finisher.run();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+ });
+ mActiveTransitions.get(transition).add(va);
+ mAnimExecutor.execute(va::start);
+ }
+
+ private static boolean isOpeningType(@WindowManager.TransitionType int legacyType) {
+ // TODO(shell-transitions): consider providing and using z-order vs the global type for
+ // this determination.
+ return legacyType == WindowManager.TRANSIT_TASK_OPEN
+ || legacyType == WindowManager.TRANSIT_TASK_TO_FRONT
+ || legacyType == WindowManager.TRANSIT_TASK_OPEN_BEHIND
+ || legacyType == WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+ }
+
+ @Override
+ public void onTransitionReady(@NonNull IBinder transitionToken, TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
+ transitionToken, info);
+ // start task
+ mMainExecutor.execute(() -> {
+ if (!mActiveTransitions.containsKey(transitionToken)) {
+ Slog.e(TAG, "Got transitionReady for non-active transition " + transitionToken
+ + " expecting one of " + mActiveTransitions.keySet());
+ }
+ if (mActiveTransitions.get(transitionToken) != null) {
+ throw new IllegalStateException("Got a duplicate onTransitionReady call for "
+ + transitionToken);
+ }
+ mActiveTransitions.put(transitionToken, new ArrayList<>());
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ final SurfaceControl leash = info.getChanges().get(i).getLeash();
+ final int mode = info.getChanges().get(i).getMode();
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
+ t.show(leash);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ if (isOpeningType(info.getType())) {
+ t.setAlpha(leash, 0.f);
+ startExampleAnimation(transitionToken, leash, true /* show */);
+ } else {
+ t.setAlpha(leash, 1.f);
+ }
+ } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_HIDE) {
+ if (!isOpeningType(info.getType())) {
+ startExampleAnimation(transitionToken, leash, false /* show */);
+ }
+ }
+ }
+ t.apply();
+ onFinish(transitionToken);
+ });
+ }
+
+ @MainThread
+ private void onFinish(IBinder transition) {
+ if (!mActiveTransitions.get(transition).isEmpty()) return;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "Transition animations finished, notifying core %s", transition);
+ mActiveTransitions.remove(transition);
+ mOrganizer.finishTransition(transition, null, null);
+ }
+
+ @Override
+ public void requestStartTransition(int type, @NonNull IBinder transitionToken) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: type=%d %s",
+ type, transitionToken);
+ mMainExecutor.execute(() -> {
+ if (mActiveTransitions.containsKey(transitionToken)) {
+ throw new RuntimeException("Transition already started " + transitionToken);
+ }
+ IBinder transition = mOrganizer.startTransition(type, transitionToken, null /* wct */);
+ mActiveTransitions.put(transition, null);
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
index 178d472..acb9a5da 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -22,7 +22,7 @@
import android.os.RemoteException;
import android.view.WindowManagerGlobal;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder;
/**
* The singleton wrapper to communicate between WindowManagerService and WMShell features
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FloatProperties.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/animation/FloatProperties.kt
index a284a74..d4f8282 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FloatProperties.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util.animation
+package com.android.wm.shell.animation
import android.graphics.Rect
import android.graphics.RectF
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index b794b91..416ada7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -24,6 +24,16 @@
*/
public class Interpolators {
/**
+ * Interpolator for alpha in animation.
+ */
+ public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * Interpolator for alpha out animation.
+ */
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+
+ /**
* Interpolator for fast out linear in animation.
*/
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
index 2a5424c..5cd660a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util.animation
+package com.android.wm.shell.animation
import android.os.Looper
import android.util.ArrayMap
@@ -26,7 +26,7 @@
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
-import com.android.systemui.util.animation.PhysicsAnimator.Companion.getInstance
+import com.android.wm.shell.animation.PhysicsAnimator.Companion.getInstance
import java.lang.ref.WeakReference
import java.util.WeakHashMap
import kotlin.math.abs
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimatorTestUtils.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimatorTestUtils.kt
index c50eeac..86eb8da 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimatorTestUtils.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,16 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.util.animation
+package com.android.wm.shell.animation
import android.os.Handler
import android.os.Looper
import android.util.ArrayMap
import androidx.dynamicanimation.animation.FloatPropertyCompat
-import com.android.systemui.util.animation.PhysicsAnimatorTestUtils.prepareForTest
-import java.util.ArrayDeque
+import com.android.wm.shell.animation.PhysicsAnimatorTestUtils.prepareForTest
+import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+import kotlin.collections.Set
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.drop
+import kotlin.collections.forEach
+import kotlin.collections.getOrPut
+import kotlin.collections.set
+import kotlin.collections.toList
+import kotlin.collections.toTypedArray
typealias UpdateMatcher = (PhysicsAnimator.AnimationUpdate) -> Boolean
typealias UpdateFramesPerProperty<T> =
@@ -84,7 +96,7 @@
*/
@JvmStatic
fun setBlockTimeout(timeoutMs: Long) {
- this.timeoutMs = timeoutMs
+ PhysicsAnimatorTestUtils.timeoutMs = timeoutMs
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java
new file mode 100644
index 0000000..96b9f86
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java
@@ -0,0 +1,61 @@
+/*
+ * 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.wm.shell.common;
+
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+
+import android.annotation.NonNull;
+import android.os.HandlerThread;
+import android.util.Singleton;
+
+/**
+ * A singleton thread for Shell to run animations on.
+ */
+public class AnimationThread extends HandlerThread {
+ private ShellExecutor mExecutor;
+
+ private AnimationThread() {
+ super("wmshell.anim", THREAD_PRIORITY_DISPLAY);
+ }
+
+ /** Get the singleton instance of this thread */
+ public static AnimationThread instance() {
+ return sAnimationThreadSingleton.get();
+ }
+
+ /**
+ * @return a shared {@link ShellExecutor} associated with this thread
+ * @hide
+ */
+ @NonNull
+ public ShellExecutor getExecutor() {
+ if (mExecutor == null) {
+ mExecutor = new HandlerExecutor(getThreadHandler());
+ }
+ return mExecutor;
+ }
+
+ private static final Singleton<AnimationThread> sAnimationThreadSingleton =
+ new Singleton<AnimationThread>() {
+ @Override
+ protected AnimationThread create() {
+ final AnimationThread animThread = new AnimationThread();
+ animThread.start();
+ return animThread;
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
index 8946c97a..976fba5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.util;
+package com.android.wm.shell.common;
import android.content.Context;
import android.content.res.Configuration;
@@ -23,7 +23,7 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Circular view with a semitransparent, circular background with an 'X' inside it.
diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
index bcfb2af..d5d072a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/FloatingContentCoordinator.kt
@@ -1,9 +1,24 @@
-package com.android.systemui.util
+/*
+ * 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.wm.shell.common
import android.graphics.Rect
import android.util.Log
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.util.FloatingContentCoordinator.FloatingContent
+import com.android.wm.shell.common.FloatingContentCoordinator.FloatingContent
import java.util.HashMap
/** Tag for debug logging. */
@@ -20,7 +35,6 @@
* no longer visible.
*/
-@SysUISingleton
class FloatingContentCoordinator constructor() {
/**
* Represents a piece of floating content, such as PIP or the Bubbles stack. Provides methods
@@ -260,14 +274,18 @@
// Lazily calculate the closest possible new tops for the content, above and below its
// current location.
- val newContentBoundsAbove by lazy { findAreaForContentAboveOrBelow(
- contentRect,
- exclusionRects = rectsToAvoidAbove.plus(newlyOverlappingRect),
- findAbove = true) }
- val newContentBoundsBelow by lazy { findAreaForContentAboveOrBelow(
- contentRect,
- exclusionRects = rectsToAvoidBelow.plus(newlyOverlappingRect),
- findAbove = false) }
+ val newContentBoundsAbove by lazy {
+ findAreaForContentAboveOrBelow(
+ contentRect,
+ exclusionRects = rectsToAvoidAbove.plus(newlyOverlappingRect),
+ findAbove = true)
+ }
+ val newContentBoundsBelow by lazy {
+ findAreaForContentAboveOrBelow(
+ contentRect,
+ exclusionRects = rectsToAvoidBelow.plus(newlyOverlappingRect),
+ findAbove = false)
+ }
val positionAboveInBounds by lazy { allowedBounds.contains(newContentBoundsAbove) }
val positionBelowInBounds by lazy { allowedBounds.contains(newContentBoundsBelow) }
@@ -347,4 +365,4 @@
(r1.right <= r2.right && r1.right >= r2.left)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
new file mode 100644
index 0000000..cd75840
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.wm.shell.common;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+/** Executor implementation which is backed by a Handler. */
+public class HandlerExecutor implements ShellExecutor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = handler;
+ }
+
+ @Override
+ public void executeDelayed(@NonNull Runnable r, long delayMillis) {
+ if (!mHandler.postDelayed(r, delayMillis)) {
+ throw new RuntimeException(mHandler + " is probably exiting");
+ }
+ }
+
+ @Override
+ public void removeCallbacks(@NonNull Runnable r) {
+ mHandler.removeCallbacks(r);
+ }
+
+ @Override
+ public void execute(@NonNull Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RuntimeException(mHandler + " is probably exiting");
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
new file mode 100644
index 0000000..aafe240
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.wm.shell.common;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Super basic Executor interface that adds support for delayed execution and removing callbacks.
+ * Intended to wrap Handler while better-supporting testing.
+ */
+public interface ShellExecutor extends Executor {
+ /**
+ * See {@link android.os.Handler#postDelayed(Runnable, long)}.
+ */
+ void executeDelayed(Runnable r, long delayMillis);
+
+ /**
+ * See {@link android.os.Handler#removeCallbacks}.
+ */
+ void removeCallbacks(Runnable r);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
index f441049..b4d7387 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.util.magnetictarget
+package com.android.wm.shell.common.magnetictarget
import android.annotation.SuppressLint
import android.content.Context
@@ -31,7 +31,7 @@
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringForce
-import com.android.systemui.util.animation.PhysicsAnimator
+import com.android.wm.shell.animation.PhysicsAnimator
import kotlin.math.abs
import kotlin.math.hypot
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
similarity index 98%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 2091baa..993e0e7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.shared.system;
+package com.android.wm.shell.pip;
import android.app.RemoteAction;
import android.content.ComponentName;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/pip/Pip.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 2b11550..7c26251 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.media.session.MediaController;
-import com.android.systemui.pip.phone.PipTouchHandler;
-import com.android.systemui.pip.tv.PipController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.pip.tv.PipController;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -31,14 +32,14 @@
*/
public interface Pip {
/**
- * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called.
+ * Registers {@link com.android.wm.shell.pip.tv.PipController.Listener} that gets called.
* whenever receiving notification on changes in PIP.
*/
default void addListener(PipController.Listener listener) {
}
/**
- * Registers a {@link com.android.systemui.pip.tv.PipController.MediaListener} to PipController.
+ * Registers a {@link PipController.MediaListener} to PipController.
*/
default void addMediaListener(PipController.MediaListener listener) {
}
@@ -72,7 +73,13 @@
return -1;
}
- default PipTouchHandler getPipTouchHandler() {
+ /**
+ * Get the touch handler which manages all the touch handling for PIP on the Phone,
+ * including moving, dismissing and expanding the PIP. (Do not used in TV)
+ *
+ * @return
+ */
+ default @Nullable PipTouchHandler getPipTouchHandler() {
return null;
}
@@ -167,7 +174,7 @@
}
/**
- * Removes a {@link com.android.systemui.pip.tv.PipController.MediaListener} from PipController.
+ * Removes a {@link PipController.MediaListener} from PipController.
*/
default void removeMediaListener(PipController.MediaListener listener) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 52ce7fe..d829462 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -26,7 +26,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.Interpolators;
+import com.android.wm.shell.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -86,12 +86,13 @@
return handler;
});
- PipAnimationController(PipSurfaceTransactionHelper helper) {
+ public PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
@SuppressWarnings("unchecked")
- PipTransitionAnimator getAnimator(SurfaceControl leash,
+ @VisibleForTesting
+ public PipTransitionAnimator getAnimator(SurfaceControl leash,
Rect destinationBounds, float alphaStart, float alphaEnd) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
@@ -108,7 +109,8 @@
}
@SuppressWarnings("unchecked")
- PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds,
+ @VisibleForTesting
+ public PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds,
Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
@@ -234,20 +236,23 @@
@Override public void onAnimationRepeat(Animator animation) {}
- @AnimationType int getAnimationType() {
+ @VisibleForTesting
+ @AnimationType public int getAnimationType() {
return mAnimationType;
}
- PipTransitionAnimator<T> setPipAnimationCallback(PipAnimationCallback callback) {
+ @VisibleForTesting
+ public PipTransitionAnimator<T> setPipAnimationCallback(PipAnimationCallback callback) {
mPipAnimationCallback = callback;
return this;
}
-
- @TransitionDirection int getTransitionDirection() {
+ @VisibleForTesting
+ @TransitionDirection public int getTransitionDirection() {
return mTransitionDirection;
}
- PipTransitionAnimator<T> setTransitionDirection(@TransitionDirection int direction) {
+ @VisibleForTesting
+ public PipTransitionAnimator<T> setTransitionDirection(@TransitionDirection int direction) {
if (direction != TRANSITION_DIRECTION_SAME) {
mTransitionDirection = direction;
}
@@ -258,7 +263,8 @@
return mStartValue;
}
- T getEndValue() {
+ @VisibleForTesting
+ public T getEndValue() {
return mEndValue;
}
@@ -295,7 +301,7 @@
* animation. In which case we can update the end bounds and keep the existing animation
* running instead of cancelling it.
*/
- void updateEndValue(T endValue) {
+ public void updateEndValue(T endValue) {
mEndValue = endValue;
}
@@ -304,7 +310,7 @@
}
@VisibleForTesting
- void setSurfaceControlTransactionFactory(
+ public void setSurfaceControlTransactionFactory(
PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
mSurfaceControlTransactionFactory = factory;
}
@@ -353,7 +359,7 @@
}
@Override
- void updateEndValue(Float endValue) {
+ public void updateEndValue(Float endValue) {
super.updateEndValue(endValue);
mStartValue = mCurrentValue;
}
@@ -444,7 +450,7 @@
}
@Override
- void updateEndValue(Rect endValue) {
+ public void updateEndValue(Rect endValue) {
super.updateEndValue(endValue);
if (mStartValue != null && mCurrentValue != null) {
mStartValue.set(mCurrentValue);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
index 89b5c38..de3261b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -39,7 +39,6 @@
import android.view.Gravity;
import android.window.WindowContainerTransaction;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
@@ -48,7 +47,6 @@
* Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
* state changes originated from Window Manager and is the source of truth for PiP window bounds.
*/
-@SysUISingleton
public class PipBoundsHandler {
private static final String TAG = PipBoundsHandler.class.getSimpleName();
@@ -254,7 +252,7 @@
/**
* See {@link #getDestinationBounds(ComponentName, float, Rect, Size, boolean)}
*/
- Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
+ public Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
Size minimalSize) {
return getDestinationBounds(componentName, aspectRatio, bounds, minimalSize,
false /* useCurrentMinEdgeSize */);
@@ -263,7 +261,7 @@
/**
* @return {@link Rect} of the destination PiP window bounds.
*/
- Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
+ public Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
Size minimalSize, boolean useCurrentMinEdgeSize) {
if (!componentName.equals(mLastPipComponentName)) {
onResetReentryBoundsUnchecked();
@@ -288,7 +286,7 @@
return destinationBounds;
}
- float getDefaultAspectRatio() {
+ public float getDefaultAspectRatio() {
return mDefaultAspectRatio;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
index 5d23e42..820930c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
import android.content.Context;
import android.content.res.Resources;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index fc724cb..b9a5536 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
import android.content.Context;
import android.content.res.Resources;
@@ -23,13 +23,11 @@
import android.graphics.RectF;
import android.view.SurfaceControl;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.wm.shell.R;
/**
* Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
*/
-@SysUISingleton
public class PipSurfaceTransactionHelper {
private final boolean mEnableCornerRadius;
@@ -63,7 +61,7 @@
* Operates the alpha on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
float alpha) {
tx.setAlpha(leash, alpha);
return this;
@@ -73,7 +71,7 @@
* Operates the crop (and position) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect destinationBounds) {
tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
.setPosition(leash, destinationBounds.left, destinationBounds.top);
@@ -84,7 +82,7 @@
* Operates the scale (setMatrix) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds) {
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRectF.set(destinationBounds);
@@ -98,7 +96,8 @@
* Operates the scale (setMatrix) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
+ SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds, Rect insets) {
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRect.set(sourceBounds);
@@ -119,9 +118,11 @@
/**
* Resets the scale (setMatrix) on a given transaction and leash if there's any
+ *
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx,
+ SurfaceControl leash,
Rect destinationBounds) {
tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
.setPosition(leash, destinationBounds.left, destinationBounds.top);
@@ -132,7 +133,7 @@
* Operates the round corner radius on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+ public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
boolean applyCornerRadius) {
if (mEnableCornerRadius) {
tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
@@ -140,7 +141,7 @@
return this;
}
- interface SurfaceControlTransactionFactory {
+ public interface SurfaceControlTransactionFactory {
SurfaceControl.Transaction getTransaction();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 98e5794..bb501fb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
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_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
-import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
-import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
+import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
+import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
+import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -59,13 +59,13 @@
import android.window.WindowContainerTransactionCallback;
import com.android.internal.os.SomeArgs;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.phone.PipMenuActivityController;
-import com.android.systemui.pip.phone.PipUpdateThread;
-import com.android.systemui.pip.phone.PipUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.pip.phone.PipMenuActivityController;
+import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.pip.phone.PipUpdateThread;
+import com.android.wm.shell.pip.phone.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
@@ -86,9 +86,8 @@
* and files a final {@link WindowContainerTransaction} at the end of the transition.
*
* This class is also responsible for general resize/offset PiP operations within SysUI component,
- * see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
+ * see also {@link PipMotionHelper}.
*/
-@SysUISingleton
public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganizer.TaskListener,
DisplayController.OnDisplaysChangedListener {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index 22adbb7..de3bb29 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.pip;
+package com.android.wm.shell.pip;
import android.app.TaskInfo;
import android.content.pm.PackageManager;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.dagger.SysUISingleton;
/**
* Helper class that ends PiP log to UiEvent, see also go/uievent
*/
-@SysUISingleton
public class PipUiEventLogger {
private static final int INVALID_PACKAGE_UID = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index a133189..fddd547 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import android.content.Context;
import android.graphics.Rect;
@@ -27,9 +27,9 @@
import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
-import com.android.systemui.pip.PipSnapAlgorithm;
-import com.android.systemui.pip.PipTaskOrganizer;
import com.android.wm.shell.R;
+import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.PipTaskOrganizer;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java
index 7dfd99c..6b6b521 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 6253043..5193656 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
+import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -36,14 +36,13 @@
import android.view.IPinnedStackController;
import android.window.WindowContainerTransaction;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTaskOrganizer;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -51,7 +50,6 @@
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
-@SysUISingleton
public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
private static final String TAG = "PipController";
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMediaController.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMediaController.java
index a5b5092..4a8db6b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMediaController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -33,7 +33,7 @@
import android.media.session.PlaybackState;
import android.os.UserHandle;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.Collections;
@@ -46,10 +46,10 @@
*/
public class PipMediaController {
- private static final String ACTION_PLAY = "com.android.systemui.pip.phone.PLAY";
- private static final String ACTION_PAUSE = "com.android.systemui.pip.phone.PAUSE";
- private static final String ACTION_NEXT = "com.android.systemui.pip.phone.NEXT";
- private static final String ACTION_PREV = "com.android.systemui.pip.phone.PREV";
+ private static final String ACTION_PLAY = "com.android.wm.shell.pip.phone.PLAY";
+ private static final String ACTION_PAUSE = "com.android.wm.shell.pip.phone.PAUSE";
+ private static final String ACTION_NEXT = "com.android.wm.shell.pip.phone.NEXT";
+ private static final String ACTION_PREV = "com.android.wm.shell.pip.phone.PREV";
/**
* A listener interface to receive notification on changes to the media actions.
@@ -88,12 +88,13 @@
}
};
- private final MediaController.Callback mPlaybackChangedListener = new MediaController.Callback() {
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- notifyActionsChanged();
- }
- };
+ private final MediaController.Callback mPlaybackChangedListener =
+ new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ notifyActionsChanged();
+ }
+ };
private final MediaSessionManager.OnActiveSessionsChangedListener mSessionsChangedListener =
controllers -> resolveActiveMediaController(controllers);
@@ -180,26 +181,26 @@
String pauseDescription = mContext.getString(R.string.pip_pause);
mPauseAction = new RemoteAction(Icon.createWithResource(mContext,
R.drawable.pip_ic_pause_white), pauseDescription, pauseDescription,
- PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
- FLAG_UPDATE_CURRENT));
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
+ FLAG_UPDATE_CURRENT));
String playDescription = mContext.getString(R.string.pip_play);
mPlayAction = new RemoteAction(Icon.createWithResource(mContext,
R.drawable.pip_ic_play_arrow_white), playDescription, playDescription,
- PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
- FLAG_UPDATE_CURRENT));
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
+ FLAG_UPDATE_CURRENT));
String nextDescription = mContext.getString(R.string.pip_skip_to_next);
mNextAction = new RemoteAction(Icon.createWithResource(mContext,
- R.drawable.ic_skip_next_white), nextDescription, nextDescription,
- PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NEXT),
- FLAG_UPDATE_CURRENT));
+ R.drawable.pip_ic_skip_next_white), nextDescription, nextDescription,
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NEXT),
+ FLAG_UPDATE_CURRENT));
String prevDescription = mContext.getString(R.string.pip_skip_to_prev);
mPrevAction = new RemoteAction(Icon.createWithResource(mContext,
- R.drawable.ic_skip_previous_white), prevDescription, prevDescription,
- PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PREV),
- FLAG_UPDATE_CURRENT));
+ R.drawable.pip_ic_skip_previous_white), prevDescription, prevDescription,
+ PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PREV),
+ FLAG_UPDATE_CURRENT));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
index 6c23225..c53803a7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -34,8 +34,8 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.phone.PipMediaController.ActionListener;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.phone.PipMediaController.ActionListener;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 6cfed07..985cd0f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import android.content.Context;
import android.graphics.Rect;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 48ddbff..24e49f8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -23,9 +23,9 @@
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -59,8 +59,8 @@
import android.widget.ImageButton;
import android.widget.LinearLayout;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index e241219..cc86cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,16 +28,17 @@
import android.util.Log;
import android.view.Choreographer;
+import androidx.annotation.VisibleForTesting;
import androidx.dynamicanimation.animation.AnimationHandler;
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.pip.PipSnapAlgorithm;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.animation.FloatProperties;
-import com.android.systemui.util.animation.PhysicsAnimator;
-import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.animation.FloatProperties;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.PipTaskOrganizer;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -503,7 +504,8 @@
/**
* Animates the PiP to offset it from the IME or shelf.
*/
- void animateToOffset(Rect originalBounds, int offset) {
+ @VisibleForTesting
+ public void animateToOffset(Rect originalBounds, int offset) {
if (DEBUG) {
Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+ " callers=\n" + Debug.getCallers(5, " "));
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 1e3d871..ef38755 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_PINCH_RESIZE;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
@@ -42,11 +42,13 @@
import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
import com.android.wm.shell.R;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUiEventLogger;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -490,11 +492,11 @@
return mUserResizeBounds;
}
- void updateMaxSize(int maxX, int maxY) {
+ @VisibleForTesting public void updateMaxSize(int maxX, int maxY) {
mMaxSize.set(maxX, maxY);
}
- void updateMinSize(int minX, int minY) {
+ @VisibleForTesting public void updateMinSize(int minX, int minY) {
mMinSize.set(minX, minY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchGesture.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchGesture.java
index 72335db..1a3cc8b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchGesture.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
/**
* A generic interface for a touch gesture.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 1f9125da..6b31772 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
import android.annotation.SuppressLint;
import android.content.ComponentName;
@@ -55,15 +55,15 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.pip.PipAnimationController;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.util.DismissCircleView;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.animation.PhysicsAnimator;
-import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.common.DismissCircleView;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUiEventLogger;
import java.io.PrintWriter;
@@ -140,9 +140,9 @@
private Rect mInsetBounds = new Rect();
// The reference bounds used to calculate the normal/expanded target bounds
private Rect mNormalBounds = new Rect();
- @VisibleForTesting Rect mNormalMovementBounds = new Rect();
+ @VisibleForTesting public Rect mNormalMovementBounds = new Rect();
private Rect mExpandedBounds = new Rect();
- @VisibleForTesting Rect mExpandedMovementBounds = new Rect();
+ @VisibleForTesting public Rect mExpandedMovementBounds = new Rect();
private int mExpandedShortestEdgeSize;
// Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -898,17 +898,17 @@
}
@VisibleForTesting
- PipResizeGestureHandler getPipResizeGestureHandler() {
+ public PipResizeGestureHandler getPipResizeGestureHandler() {
return mPipResizeGestureHandler;
}
@VisibleForTesting
- void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
+ public void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
mPipResizeGestureHandler = pipResizeGestureHandler;
}
@VisibleForTesting
- void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
+ public void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
mMotionHelper = pipMotionHelper;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index ecd1128a..21715077 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import android.graphics.PointF;
import android.os.Handler;
@@ -35,7 +35,7 @@
private static final boolean DEBUG = false;
@VisibleForTesting
- static final long DOUBLE_TAP_TIMEOUT = 200;
+ public static final long DOUBLE_TAP_TIMEOUT = 200;
static final long HOVER_EXIT_TIMEOUT = 50;
private final Handler mHandler;
@@ -106,8 +106,8 @@
mAllowDraggingOffscreen = true;
mIsUserInteracting = true;
mDownTouchTime = ev.getEventTime();
- mIsDoubleTap = !mPreviouslyDragging &&
- (mDownTouchTime - mLastDownTouchTime) < DOUBLE_TAP_TIMEOUT;
+ mIsDoubleTap = !mPreviouslyDragging
+ && (mDownTouchTime - mLastDownTouchTime) < DOUBLE_TAP_TIMEOUT;
mIsWaitingForDoubleTap = false;
mIsDragging = false;
mLastDownTouchTime = mDownTouchTime;
@@ -163,8 +163,8 @@
final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
if (DEBUG) {
- Log.e(TAG, "Relinquish active pointer id on POINTER_UP: " +
- mActivePointerId);
+ Log.e(TAG,
+ "Relinquish active pointer id on POINTER_UP: " + mActivePointerId);
}
mLastTouch.set(ev.getRawX(newPointerIndex), ev.getRawY(newPointerIndex));
}
@@ -191,8 +191,8 @@
mUpTouchTime = ev.getEventTime();
mLastTouch.set(ev.getRawX(pointerIndex), ev.getRawY(pointerIndex));
mPreviouslyDragging = mIsDragging;
- mIsWaitingForDoubleTap = !mIsDoubleTap && !mIsDragging &&
- (mUpTouchTime - mDownTouchTime) < DOUBLE_TAP_TIMEOUT;
+ mIsWaitingForDoubleTap = !mIsDoubleTap && !mIsDragging
+ && (mUpTouchTime - mDownTouchTime) < DOUBLE_TAP_TIMEOUT;
// Fall through to clean up
}
@@ -223,7 +223,7 @@
/**
* @return the movement delta between the last handled touch event and the previous touch
- * position.
+ * position.
*/
public PointF getLastTouchDelta() {
return mLastDelta;
@@ -238,7 +238,7 @@
/**
* @return the movement delta between the last handled touch event and the down touch
- * position.
+ * position.
*/
public PointF getDownTouchDelta() {
return mDownDelta;
@@ -318,7 +318,8 @@
}
}
- @VisibleForTesting long getDoubleTapTimeoutCallbackDelay() {
+ @VisibleForTesting
+ public long getDoubleTapTimeoutCallbackDelay() {
if (mIsWaitingForDoubleTap) {
return Math.max(0, DOUBLE_TAP_TIMEOUT - (mUpTouchTime - mDownTouchTime));
}
@@ -333,7 +334,8 @@
mHandler.removeCallbacks(mDoubleTapTimeoutCallback);
}
- void scheduleHoverExitTimeoutCallback() {
+ @VisibleForTesting
+ public void scheduleHoverExitTimeoutCallback() {
mHandler.removeCallbacks(mHoverExitTimeoutCallback);
mHandler.postDelayed(mHoverExitTimeoutCallback, HOVER_EXIT_TIMEOUT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUpdateThread.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUpdateThread.java
index 6c5d846..d686cac 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUpdateThread.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import android.os.Handler;
import android.os.HandlerThread;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
index 1bf6dd7..6a58ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone;
+package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -35,7 +35,7 @@
/**
* @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
- * The component name may be null if no such activity exists.
+ * The component name may be null if no such activity exists.
*/
public static Pair<ComponentName, Integer> getTopPipActivity(Context context,
IActivityManager activityManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java
index db9bedd..4e82bb5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import android.animation.Animator;
import android.animation.AnimatorInflater;
@@ -83,9 +83,9 @@
mButtonImageView = findViewById(R.id.button);
mDescriptionTextView = findViewById(R.id.desc);
- int[] values = new int[] {android.R.attr.src, android.R.attr.text};
- TypedArray typedArray =
- context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
+ int[] values = new int[]{android.R.attr.src, android.R.attr.text};
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, values, defStyleAttr,
+ defStyleRes);
setImageResource(typedArray.getResourceId(0, 0));
setText(typedArray.getResourceId(1, 0));
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index d27f257..3eec20f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -45,13 +45,12 @@
import android.util.Log;
import android.view.DisplayInfo;
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.R;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTaskOrganizer;
import java.util.ArrayList;
import java.util.List;
@@ -59,7 +58,6 @@
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
-@SysUISingleton
public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
private static final String TAG = "PipController";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -252,6 +250,9 @@
Log.e(TAG, "Failed to register pinned stack listener", e);
}
}
+
+ // TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
+ PipMenuActivity.setPipController(this);
}
private void loadConfigurationsAndApply(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java
index 125444d..14960c3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import android.content.Context;
import android.util.AttributeSet;
@@ -30,6 +30,10 @@
*/
public class PipControlsView extends LinearLayout {
+ public PipControlsView(Context context) {
+ this(context, null);
+ }
+
public PipControlsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java
index 8c04a52..f66e902 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import android.app.PendingIntent;
import android.app.RemoteAction;
@@ -26,17 +26,13 @@
import android.view.LayoutInflater;
import android.view.View;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.Pip;
import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import javax.inject.Inject;
/**
* Controller for {@link PipControlsView}.
@@ -49,7 +45,7 @@
private final PipControlsView mView;
private final LayoutInflater mLayoutInflater;
private final Handler mHandler;
- private final Optional<Pip> mPipOptional;
+ private final PipController mPipController;
private final PipControlButtonView mPlayPauseButtonView;
private MediaController mMediaController;
private PipControlButtonView mFocusedChild;
@@ -77,14 +73,12 @@
@Override
public void onViewAttachedToWindow(View v) {
updateMediaController();
- mPipOptional.ifPresent(
- pip -> pip.addMediaListener(mPipMediaListener));
+ mPipController.addMediaListener(mPipMediaListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
- mPipOptional.ifPresent(
- pip -> pip.removeMediaListener(mPipMediaListener));
+ mPipController.removeMediaListener(mPipMediaListener);
}
};
@@ -110,12 +104,11 @@
}
};
- @Inject
- public PipControlsViewController(PipControlsView view, Optional<Pip> pipOptional,
- LayoutInflater layoutInflater, @Main Handler handler) {
+ public PipControlsViewController(PipControlsView view, PipController pipController,
+ LayoutInflater layoutInflater, Handler handler) {
super();
mView = view;
- mPipOptional = pipOptional;
+ mPipController = pipController;
mLayoutInflater = layoutInflater;
mHandler = handler;
@@ -126,34 +119,29 @@
View fullButtonView = mView.getFullButtonView();
fullButtonView.setOnFocusChangeListener(mFocusChangeListener);
- fullButtonView.setOnClickListener(
- v -> mPipOptional.ifPresent(pip -> pip.movePipToFullscreen())
- );
+ fullButtonView.setOnClickListener(mView -> mPipController.movePipToFullscreen());
View closeButtonView = mView.getCloseButtonView();
closeButtonView.setOnFocusChangeListener(mFocusChangeListener);
closeButtonView.setOnClickListener(v -> {
- mPipOptional.ifPresent(pip -> pip.closePip());
+ mPipController.closePip();
if (mListener != null) {
mListener.onClosed();
}
});
-
mPlayPauseButtonView = mView.getPlayPauseButtonView();
mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener);
mPlayPauseButtonView.setOnClickListener(v -> {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
return;
}
- mPipOptional.ifPresent(pip -> {
- final int playbackState = pip.getPlaybackState();
- if (playbackState == PipController.PLAYBACK_STATE_PAUSED) {
- mMediaController.getTransportControls().play();
- } else if (playbackState == PipController.PLAYBACK_STATE_PLAYING) {
- mMediaController.getTransportControls().pause();
- }
- });
+ final int playbackState = mPipController.getPlaybackState();
+ if (playbackState == PipController.PLAYBACK_STATE_PAUSED) {
+ mMediaController.getTransportControls().play();
+ } else if (playbackState == PipController.PLAYBACK_STATE_PLAYING) {
+ mMediaController.getTransportControls().pause();
+ }
// View will be updated later in {@link mMediaControllerCallback}
});
@@ -161,7 +149,7 @@
private void updateMediaController() {
AtomicReference<MediaController> newController = new AtomicReference<>();
- mPipOptional.ifPresent(pip -> newController.set(pip.getMediaController()));
+ newController.set(mPipController.getMediaController());
if (newController.get() == null || mMediaController == newController.get()) {
return;
@@ -224,7 +212,7 @@
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN);
- mPipOptional.ifPresent(pip -> state.set(pip.getPlaybackState()));
+ state.set(mPipController.getPlaybackState());
if (state.get() == PipController.STATE_UNKNOWN
|| state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) {
mPlayPauseButtonView.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java
similarity index 77%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java
index 7e812d9..06d2408 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import android.animation.Animator;
import android.animation.AnimatorInflater;
@@ -25,59 +25,40 @@
import android.os.Bundle;
import android.util.Log;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.tv.dagger.TvPipComponent;
import com.android.wm.shell.R;
import java.util.Collections;
-import java.util.Optional;
-
-import javax.inject.Inject;
/**
* Activity to show the PIP menu to control PIP.
+ * TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
*/
-
public class PipMenuActivity extends Activity implements PipController.Listener {
private static final String TAG = "PipMenuActivity";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
- private final TvPipComponent.Builder mPipComponentBuilder;
- private TvPipComponent mTvPipComponent;
- private final Optional<Pip> mPipOptional;
+ private static PipController sPipController;
private Animator mFadeInAnimation;
private Animator mFadeOutAnimation;
private boolean mRestorePipSizeWhenClose;
private PipControlsViewController mPipControlsViewController;
- @Inject
- public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder,
- Optional<Pip> pipOptional) {
- super();
- mPipComponentBuilder = pipComponentBuilder;
- mPipOptional = pipOptional;
- }
-
@Override
protected void onCreate(Bundle bundle) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(bundle);
- mPipOptional.ifPresent(pip -> {
- if (!pip.isPipShown()) {
- finish();
- }
- });
+ if (sPipController == null || sPipController.isPipShown()) {
+ finish();
+ }
setContentView(R.layout.tv_pip_menu);
- mTvPipComponent = mPipComponentBuilder.pipControlsView(
- findViewById(R.id.pip_controls)).build();
- mPipControlsViewController = mTvPipComponent.getPipControlsViewController();
-
- mPipOptional.ifPresent(pip -> pip.addListener(this));
-
+ mPipControlsViewController = new PipControlsViewController(
+ findViewById(R.id.pip_controls), sPipController,
+ getLayoutInflater(), getApplicationContext().getMainThreadHandler());
+ sPipController.addListener(this);
mRestorePipSizeWhenClose = true;
mFadeInAnimation = AnimatorInflater.loadAnimator(
this, R.anim.tv_pip_menu_fade_in_animation);
@@ -104,7 +85,7 @@
if (DEBUG) Log.d(TAG, " > restoring to the default position");
// When PIP menu activity is closed, restore to the default position.
- mPipOptional.ifPresent(pip -> pip.resizePinnedStack(PipController.STATE_PIP));
+ sPipController.resizePinnedStack(PipController.STATE_PIP);
}
finish();
}
@@ -131,9 +112,9 @@
if (DEBUG) Log.d(TAG, "onDestroy()");
super.onDestroy();
- mPipOptional.ifPresent(pip -> pip.removeListener(this));
- mPipOptional.ifPresent(pip -> pip.resumePipResizing(
- PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
+ sPipController.removeListener(this);
+ sPipController.resumePipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
@Override
@@ -184,8 +165,8 @@
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
finish();
- mPipOptional.ifPresent(pip -> pip.suspendPipResizing(
- PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
+ sPipController.suspendPipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
@Override
@@ -194,4 +175,16 @@
super.finish();
}
+
+ /**
+ * TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
+ *
+ * @param pipController The singleton pipController instance for TV
+ */
+ public static void setPipController(PipController pipController) {
+ if (sPipController != null) {
+ return;
+ }
+ sPipController = pipController;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
index 0666811..7433085 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv;
+package com.android.wm.shell.pip.tv;
import android.app.Notification;
import android.app.NotificationManager;
@@ -37,7 +37,6 @@
import android.util.Log;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.util.NotificationChannels;
import com.android.wm.shell.R;
/**
@@ -53,6 +52,8 @@
private static final String ACTION_MENU = "PipNotification.menu";
private static final String ACTION_CLOSE = "PipNotification.close";
+ public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP";
+
private final PackageManager mPackageManager;
private final PipController mPipController;
@@ -169,7 +170,7 @@
mNotificationManager = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
- mNotificationBuilder = new Notification.Builder(context, NotificationChannels.TVPIP)
+ mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP)
.setLocalOnly(true)
.setOngoing(false)
.setCategory(Notification.CATEGORY_SYSTEM)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index e3029e5..a0ce9da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -28,6 +28,8 @@
// with those in the framework ProtoLogGroup
WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
+ WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ Consts.TAG_WM_SHELL),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
index cdb27da..2b14e8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
@@ -845,15 +845,7 @@
}
void enterSplitMode(boolean isHomeStackResizable) {
- post(() -> {
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- t.show(sc).apply();
- mTiles.releaseTransaction(t);
- });
+ setHidden(false);
SnapTarget miniMid =
mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget();
@@ -880,14 +872,19 @@
}
void exitSplitMode() {
- // Reset tile bounds
+ // The view is going to be removed right after this function involved, updates the surface
+ // in the current thread instead of posting it to the view's UI thread.
final SurfaceControl sc = getWindowSurfaceControl();
if (sc == null) {
return;
}
Transaction t = mTiles.getTransaction();
- t.hide(sc).apply();
+ t.hide(sc);
+ mImeController.setDimsHidden(t, true);
+ t.apply();
mTiles.releaseTransaction(t);
+
+ // Reset tile bounds
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 937b00b..9940ea5 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -23,20 +23,30 @@
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "androidx.dynamicanimation_dynamicanimation",
+ "dagger2",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
"mockito-target-extended-minus-junit4",
"truth-prebuilt",
"testables",
],
+
libs: [
"android.test.mock",
"android.test.base",
"android.test.runner",
],
+
jni_libs: [
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
],
+ kotlincflags: ["-Xjvm-default=enable"],
+
+ plugins: ["dagger2-compiler"],
+
optimize: {
enabled: false,
},
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 823e0b7..1bc5cea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -33,7 +33,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.TransactionPool;
import org.junit.Before;
import org.junit.Test;
@@ -55,6 +57,8 @@
ShellTaskOrganizer mOrganizer;
private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
+ private final TransactionPool mTransactionPool = mock(TransactionPool.class);
+ private final ShellExecutor mTestExecutor = mock(ShellExecutor.class);
private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
@@ -85,7 +89,8 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue);
+ mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
+ mTransactionPool, mTestExecutor, mTestExecutor);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/animation/PhysicsAnimatorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/animation/PhysicsAnimatorTest.kt
index bd59680..4bd9bed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/animation/PhysicsAnimatorTest.kt
@@ -1,4 +1,20 @@
-package com.android.systemui.util.animation
+/*
+ * 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.wm.shell.animation
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -11,11 +27,11 @@
import androidx.dynamicanimation.animation.SpringForce
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.animation.PhysicsAnimator.EndListener
-import com.android.systemui.util.animation.PhysicsAnimator.UpdateListener
-import com.android.systemui.util.animation.PhysicsAnimatorTestUtils.clearAnimationUpdateFrames
-import com.android.systemui.util.animation.PhysicsAnimatorTestUtils.getAnimationUpdateFrames
-import com.android.systemui.util.animation.PhysicsAnimatorTestUtils.verifyAnimationUpdateFrames
+import com.android.wm.shell.animation.PhysicsAnimator.EndListener
+import com.android.wm.shell.animation.PhysicsAnimator.UpdateListener
+import com.android.wm.shell.animation.PhysicsAnimatorTestUtils.clearAnimationUpdateFrames
+import com.android.wm.shell.animation.PhysicsAnimatorTestUtils.getAnimationUpdateFrames
+import com.android.wm.shell.animation.PhysicsAnimatorTestUtils.verifyAnimationUpdateFrames
import org.junit.After
import org.junit.Assert
import org.junit.Assert.assertEquals
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt
index 251ca9c..fe53641 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/magnetictarget/MagnetizedObjectTest.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.util.magnetictarget
+package com.android.wm.shell.common.magnetictarget
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
similarity index 93%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 89ca32c..7d51886 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -16,8 +16,8 @@
package com.android.systemui.pip;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -32,7 +32,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -47,7 +49,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipAnimationControllerTest extends SysuiTestCase {
+public class PipAnimationControllerTest extends PipTestCase {
private PipAnimationController mPipAnimationController;
@@ -161,7 +163,7 @@
* A dummy {@link SurfaceControl.Transaction} class.
* This is created as {@link Mock} does not support method chaining.
*/
- private static class DummySurfaceControlTx extends SurfaceControl.Transaction {
+ public static class DummySurfaceControlTx extends SurfaceControl.Transaction {
@Override
public SurfaceControl.Transaction setAlpha(SurfaceControl leash, float alpha) {
return this;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
index cdb1770..f514b0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
@@ -31,7 +31,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -46,7 +47,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipBoundsHandlerTest extends SysuiTestCase {
+public class PipBoundsHandlerTest extends PipTestCase {
private static final int ROUNDING_ERROR_MARGIN = 16;
private static final float ASPECT_RATIO_ERROR_MARGIN = 0.01f;
private static final float DEFAULT_ASPECT_RATIO = 1f;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java
new file mode 100644
index 0000000..fdebe4e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.wm.shell.pip;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+
+/**
+ * Base class that does One Handed specific setup.
+ */
+public abstract class PipTestCase {
+
+ protected TestableContext mContext;
+
+ @Before
+ public void setup() {
+ final Context context =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final DisplayManager dm = context.getSystemService(DisplayManager.class);
+ mContext = new TestableContext(
+ context.createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY)));
+
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ }
+
+ protected Context getContext() {
+ return mContext;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
similarity index 71%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 1274621..d305c64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -31,13 +31,15 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.pip.phone.PipAppOpsListener;
+import com.android.wm.shell.pip.phone.PipController;
+import com.android.wm.shell.pip.phone.PipMediaController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import org.junit.Before;
import org.junit.Test;
@@ -51,15 +53,14 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipControllerTest extends SysuiTestCase {
- private PipController mPipController;
+public class PipControllerTest extends PipTestCase {
+ private com.android.wm.shell.pip.phone.PipController mPipController;
private TestableContext mSpiedContext;
- @Mock private ActivityManagerWrapper mMockActivityManagerWrapper;
- @Mock private ConfigurationController mMockConfigurationController;
@Mock private DisplayController mMockdDisplayController;
@Mock private PackageManager mPackageManager;
- @Mock private PipMenuActivityController mMockPipMenuActivityController;
+ @Mock private com.android.wm.shell.pip.phone.PipMenuActivityController
+ mMockPipMenuActivityController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsHandler mMockPipBoundsHandler;
@Mock private PipMediaController mMockPipMediaController;
@@ -77,14 +78,9 @@
when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
mPipController = new PipController(mSpiedContext, mMockdDisplayController,
- mMockPipAppOpsListener,
- mMockPipBoundsHandler, mMockPipMediaController, mMockPipMenuActivityController,
- mMockPipTaskOrganizer, mMockPipTouchHandler, mMockWindowManagerShellWrapper);
- }
-
- @Test
- public void testNonPipDevice_shouldNotRegisterTaskStackListener() {
- verify(mMockActivityManagerWrapper, never()).registerTaskStackListener(any());
+ mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipMediaController,
+ mMockPipMenuActivityController, mMockPipTaskOrganizer, mMockPipTouchHandler,
+ mMockWindowManagerShellWrapper);
}
@Test
@@ -101,9 +97,4 @@
public void testNonPipDevice_shouldNotAddDisplayWindowListener() {
verify(mMockdDisplayController, never()).addDisplayWindowListener(any());
}
-
- @Test
- public void testNonPipDevice_shouldNotAddCallback() {
- verify(mMockConfigurationController, never()).addCallback(any());
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTaskOrganizerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
index b1a7df8..663169f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTaskOrganizerTest.java
@@ -32,13 +32,13 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -55,7 +55,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipTaskOrganizerTest extends SysuiTestCase {
+public class PipTaskOrganizerTest extends PipTestCase {
private PipTaskOrganizer mSpiedPipTaskOrganizer;
private TestableContext mSpiedContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
similarity index 89%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index ad83ebb..c96cb20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -30,13 +30,17 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PipMenuActivityController;
+import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.pip.phone.PipResizeGestureHandler;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import org.junit.Before;
import org.junit.Test;
@@ -54,7 +58,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipTouchHandlerTest extends SysuiTestCase {
+public class PipTouchHandlerTest extends PipTestCase {
private PipTouchHandler mPipTouchHandler;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
index 17b2e32..2702130 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.systemui.pip.phone;
@@ -35,7 +35,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.pip.phone.PipTouchState;
import org.junit.Before;
import org.junit.Test;
@@ -46,7 +47,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@RunWithLooper
-public class PipTouchStateTest extends SysuiTestCase {
+public class PipTouchStateTest extends PipTestCase {
private PipTouchState mTouchState;
private CountDownLatch mDoubleTapCallbackTriggeredLatch;
@@ -157,4 +158,4 @@
private MotionEvent createMotionEvent(int action, long eventTime, float x, float y) {
return MotionEvent.obtain(0, eventTime, action, x, y, 0);
}
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 975265e..155bb6b 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -464,14 +464,6 @@
"RenderNode.cpp",
"RenderProperties.cpp",
"RootRenderNode.cpp",
- "shader/Shader.cpp",
- "shader/BitmapShader.cpp",
- "shader/BlurShader.cpp",
- "shader/ComposeShader.cpp",
- "shader/LinearGradientShader.cpp",
- "shader/RadialGradientShader.cpp",
- "shader/RuntimeShader.cpp",
- "shader/SweepGradientShader.cpp",
"SkiaCanvas.cpp",
"VectorDrawable.cpp",
],
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index a690840..1dbce58 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -42,8 +42,6 @@
#include <SkTextBlob.h>
#include <SkVertices.h>
-#include <shader/BitmapShader.h>
-
#include <memory>
#include <optional>
#include <utility>
@@ -51,7 +49,6 @@
namespace android {
using uirenderer::PaintUtils;
-using uirenderer::BitmapShader;
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
@@ -684,9 +681,7 @@
if (paint) {
pnt = *paint;
}
-
- pnt.setShader(sk_ref_sp(new BitmapShader(
- bitmap.makeImage(), SkTileMode::kClamp, SkTileMode::kClamp, nullptr)));
+ pnt.setShader(bitmap.makeImage()->makeShader());
auto v = builder.detach();
apply_looper(&pnt, [&](const SkPaint& p) {
mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 0f566e4..cd908354 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -23,6 +23,7 @@
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
+#include "SkShader.h"
#include "hwui/Paint.h"
#ifdef __ANDROID__
@@ -158,10 +159,10 @@
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
- Paint paint;
+ SkPaint paint;
if (properties.getFillGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
- paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getFillGradient())));
+ paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getFillGradient())));
needsFill = true;
} else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
@@ -178,7 +179,7 @@
bool needsStroke = false;
if (properties.getStrokeGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
- paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getStrokeGradient())));
+ paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getStrokeGradient())));
needsStroke = true;
} else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index d4086f1..ac7d41e 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,8 +31,8 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
+#include <SkShader.h>
#include <SkSurface.h>
-#include <shader/Shader.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -227,20 +227,20 @@
strokeGradient = prop.strokeGradient;
onPropertyChanged();
}
- void setFillGradient(Shader* gradient) {
+ void setFillGradient(SkShader* gradient) {
if (fillGradient.get() != gradient) {
fillGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- void setStrokeGradient(Shader* gradient) {
+ void setStrokeGradient(SkShader* gradient) {
if (strokeGradient.get() != gradient) {
strokeGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- Shader* getFillGradient() const { return fillGradient.get(); }
- Shader* getStrokeGradient() const { return strokeGradient.get(); }
+ SkShader* getFillGradient() const { return fillGradient.get(); }
+ SkShader* getStrokeGradient() const { return strokeGradient.get(); }
float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
@@ -320,8 +320,8 @@
count,
};
PrimitiveFields mPrimitiveFields;
- sk_sp<Shader> fillGradient;
- sk_sp<Shader> strokeGradient;
+ sk_sp<SkShader> fillGradient;
+ sk_sp<SkShader> strokeGradient;
};
// Called from UI thread
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 2001b56..8df2770b 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -73,7 +73,7 @@
static void simplifyPaint(int color, Paint* paint) {
paint->setColor(color);
- paint->setShader((sk_sp<uirenderer::Shader>)nullptr);
+ paint->setShader(nullptr);
paint->setColorFilter(nullptr);
paint->setLooper(nullptr);
paint->setStrokeWidth(4 + 0.04 * paint->getSkFont().getSize());
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index 2989676..77a2142 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -49,6 +49,8 @@
void GetFontExtent(minikin::MinikinExtent* extent, const minikin::MinikinPaint& paint,
const minikin::FontFakery& fakery) const override;
+ const std::string& GetFontPath() const override { return mFilePath; }
+
SkTypeface* GetSkTypeface() const;
sk_sp<SkTypeface> RefSkTypeface() const;
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 4e2016a..e75e9e7 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -30,8 +30,6 @@
#include <minikin/FamilyVariant.h>
#include <minikin/Hyphenator.h>
-#include <shader/Shader.h>
-
namespace android {
class Paint : public SkPaint {
@@ -151,13 +149,8 @@
// The only respected flags are : [ antialias, dither, filterBitmap ]
static uint32_t GetSkPaintJavaFlags(const SkPaint&);
static void SetSkPaintJavaFlags(SkPaint*, uint32_t flags);
-
- void setShader(sk_sp<uirenderer::Shader> shader);
private:
-
- using SkPaint::setShader;
-
SkFont mFont;
sk_sp<SkDrawLooper> mLooper;
@@ -176,7 +169,6 @@
bool mStrikeThru = false;
bool mUnderline = false;
bool mDevKern = false;
- sk_sp<uirenderer::Shader> mShader;
};
} // namespace android
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 21f60fd..fa2674f 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -24,8 +24,7 @@
, mWordSpacing(0)
, mFontFeatureSettings()
, mMinikinLocaleListId(0)
- , mFamilyVariant(minikin::FamilyVariant::DEFAULT)
- , mShader(nullptr) {
+ , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {
// SkPaint::antialiasing defaults to false, but
// SkFont::edging defaults to kAntiAlias. To keep them
// insync, we manually set the font to kAilas.
@@ -46,8 +45,7 @@
, mAlign(paint.mAlign)
, mStrikeThru(paint.mStrikeThru)
, mUnderline(paint.mUnderline)
- , mDevKern(paint.mDevKern)
- , mShader(paint.mShader){}
+ , mDevKern(paint.mDevKern) {}
Paint::~Paint() {}
@@ -67,30 +65,9 @@
mStrikeThru = other.mStrikeThru;
mUnderline = other.mUnderline;
mDevKern = other.mDevKern;
- mShader = other.mShader;
return *this;
}
-void Paint::setShader(sk_sp<uirenderer::Shader> shader) {
- if (shader) {
- // If there is an SkShader compatible shader, apply it
- sk_sp<SkShader> skShader = shader->asSkShader();
- if (skShader.get()) {
- SkPaint::setShader(skShader);
- SkPaint::setImageFilter(nullptr);
- } else {
- // ... otherwise the specified shader can only be represented as an ImageFilter
- SkPaint::setShader(nullptr);
- SkPaint::setImageFilter(shader->asSkImageFilter());
- }
- } else {
- // No shader is provided at all, clear out both the SkShader and SkImageFilter slots
- SkPaint::setShader(nullptr);
- SkPaint::setImageFilter(nullptr);
- }
- mShader = shader;
-}
-
bool operator==(const Paint& a, const Paint& b) {
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
a.mFont == b.mFont &&
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index ccc328c..03f1d62 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -188,7 +188,7 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, kRobotoFont, 0,
std::vector<minikin::FontVariation>());
- std::vector<minikin::Font> fonts;
+ std::vector<std::shared_ptr<minikin::Font>> fonts;
fonts.push_back(minikin::Font::Builder(font).build());
std::shared_ptr<minikin::FontCollection> collection = std::make_shared<minikin::FontCollection>(
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index 68eaa0a..2e85840 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -42,7 +42,7 @@
: langId(langId), variant(static_cast<minikin::FamilyVariant>(variant)) {}
uint32_t langId;
minikin::FamilyVariant variant;
- std::vector<minikin::Font> fonts;
+ std::vector<std::shared_ptr<minikin::Font>> fonts;
std::vector<minikin::FontVariation> axes;
};
diff --git a/libs/hwui/jni/FontUtils.h b/libs/hwui/jni/FontUtils.h
index f93a0da..ba4e56e 100644
--- a/libs/hwui/jni/FontUtils.h
+++ b/libs/hwui/jni/FontUtils.h
@@ -19,6 +19,7 @@
#include <jni.h>
#include <memory>
+#include <utility>
#include <minikin/Font.h>
@@ -34,18 +35,10 @@
};
struct FontWrapper {
- FontWrapper(minikin::Font&& font) : font(std::move(font)) {}
- minikin::Font font;
+ explicit FontWrapper(std::shared_ptr<minikin::Font>&& font) : font(font) {}
+ std::shared_ptr<minikin::Font> font;
};
-// We assume FontWrapper's address is the same as underlying Font's address.
-// This assumption is used for looking up Java font object from native address.
-// The Font object can be created without Java's Font object but all Java's Font objects point to
-// the native FontWrapper. So when looking up Java object from minikin::Layout which gives us Font
-// address, we lookup Font Java object from Font address with assumption that it is the same as
-// FontWrapper address.
-static_assert(offsetof(FontWrapper, font) == 0);
-
// Utility wrapper for java.util.List
class ListHelper {
public:
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index f6c8496..3c86b28 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -47,7 +47,6 @@
#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <minikin/MinikinPaint.h>
-#include <shader/Shader.h>
#include <unicode/utf16.h>
#include <cassert>
@@ -55,8 +54,6 @@
#include <memory>
#include <vector>
-using namespace android::uirenderer;
-
namespace android {
static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count,
@@ -745,10 +742,11 @@
return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
}
- static void setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
- auto* paint = reinterpret_cast<Paint*>(objHandle);
- auto* shader = reinterpret_cast<Shader*>(shaderHandle);
- paint->setShader(sk_ref_sp(shader));
+ static jlong setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
+ obj->setShader(sk_ref_sp(shader));
+ return reinterpret_cast<jlong>(obj->getShader());
}
static jlong setColorFilter(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong filterHandle) {
@@ -1059,7 +1057,7 @@
{"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
{"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
{"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
- {"nSetShader","(JJ)V", (void*) PaintGlue::setShader},
+ {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
{"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
{"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
{"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0a194f9..e76aace 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -5,14 +5,6 @@
#include "SkShader.h"
#include "SkBlendMode.h"
#include "include/effects/SkRuntimeEffect.h"
-#include "shader/Shader.h"
-#include "shader/BitmapShader.h"
-#include "shader/BlurShader.h"
-#include "shader/ComposeShader.h"
-#include "shader/LinearGradientShader.h"
-#include "shader/RadialGradientShader.h"
-#include "shader/RuntimeShader.h"
-#include "shader/SweepGradientShader.h"
#include <vector>
@@ -58,7 +50,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Shader_safeUnref(Shader* shader) {
+static void Shader_safeUnref(SkShader* shader) {
SkSafeUnref(shader);
}
@@ -82,15 +74,15 @@
SkBitmap bitmap;
image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
}
+ sk_sp<SkShader> shader = image->makeShader(
+ (SkTileMode)tileModeX, (SkTileMode)tileModeY);
+ ThrowIAE_IfNull(env, shader.get());
- auto* shader = new BitmapShader(
- image,
- static_cast<SkTileMode>(tileModeX),
- static_cast<SkTileMode>(tileModeY),
- matrix
- );
+ if (matrix) {
+ shader = shader->makeWithLocalMatrix(*matrix);
+ }
- return reinterpret_cast<jlong>(shader);
+ return reinterpret_cast<jlong>(shader.release());
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -126,18 +118,17 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- auto* shader = new LinearGradientShader(
- pts,
- colors,
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
- pos,
- static_cast<SkTileMode>(tileMode),
- sGradientShaderFlags,
- matrix
- );
+ sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
+ static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
+ ThrowIAE_IfNull(env, shader);
- return reinterpret_cast<jlong>(shader);
+ const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ if (matrix) {
+ shader = shader->makeWithLocalMatrix(*matrix);
+ }
+
+ return reinterpret_cast<jlong>(shader.release());
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -157,20 +148,17 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
+ static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
+ ThrowIAE_IfNull(env, shader);
- auto* shader = new RadialGradientShader(
- center,
- radius,
- colors,
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
- pos,
- static_cast<SkTileMode>(tileMode),
- sGradientShaderFlags,
- matrix
- );
+ const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ if (matrix) {
+ shader = shader->makeWithLocalMatrix(*matrix);
+ }
- return reinterpret_cast<jlong>(shader);
+ return reinterpret_cast<jlong>(shader.release());
}
///////////////////////////////////////////////////////////////////////////////
@@ -186,75 +174,54 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
+ sGradientShaderFlags, nullptr);
+ ThrowIAE_IfNull(env, shader);
- auto* shader = new SweepGradientShader(
- x,
- y,
- colors,
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
- pos,
- sGradientShaderFlags,
- matrix
- );
+ const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ if (matrix) {
+ shader = shader->makeWithLocalMatrix(*matrix);
+ }
- return reinterpret_cast<jlong>(shader);
+ return reinterpret_cast<jlong>(shader.release());
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- auto* shaderA = reinterpret_cast<Shader*>(shaderAHandle);
- auto* shaderB = reinterpret_cast<Shader*>(shaderBHandle);
+ const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
+ SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
+ SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
+ sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
+ sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
- auto mode = static_cast<SkBlendMode>(xfermodeHandle);
+ SkShader* shader;
- auto* composeShader = new ComposeShader(
- *shaderA,
- *shaderB,
- mode,
- matrix
- );
-
- return reinterpret_cast<jlong>(composeShader);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
- jfloat sigmaY, jlong shaderHandle, jint edgeTreatment) {
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
-
- auto* blurShader = new BlurShader(
- sigmaX,
- sigmaY,
- inputShader,
- static_cast<SkTileMode>(edgeTreatment),
- matrix
- );
- return reinterpret_cast<jlong>(blurShader);
+ if (matrix) {
+ shader = baseShader->makeWithLocalMatrix(*matrix).release();
+ } else {
+ shader = baseShader.release();
+ }
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
- auto* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
+ SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
AutoJavaByteArray arInputs(env, inputs);
- auto data = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
- auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ sk_sp<SkData> fData;
+ fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
+ const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
+ ThrowIAE_IfNull(env, shader);
- auto* shader = new RuntimeShader(
- *effect,
- std::move(data),
- isOpaque == JNI_TRUE,
- matrix
- );
- return reinterpret_cast<jlong>(shader);
+ return reinterpret_cast<jlong>(shader.release());
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -272,8 +239,12 @@
///////////////////////////////////////////////////////////////////////////////////////////////
+static void Effect_safeUnref(SkRuntimeEffect* effect) {
+ SkSafeUnref(effect);
+}
+
static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -291,10 +262,6 @@
{ "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
};
-static const JNINativeMethod gBlurShaderMethods[] = {
- { "nativeCreate", "(JFFJI)J", (void*)BlurShader_create }
-};
-
static const JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
};
@@ -326,8 +293,6 @@
NELEM(gShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
NELEM(gBitmapShaderMethods));
- android::RegisterMethodsOrDie(env, "android/graphics/BlurShader", gBlurShaderMethods,
- NELEM(gBlurShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
NELEM(gLinearGradientMethods));
android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
index a1adcb3..9cffceb 100644
--- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -143,13 +143,13 @@
static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- auto* fillShader = reinterpret_cast<Shader*>(fillGradientPtr);
+ SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
path->mutateStagingProperties()->setFillGradient(fillShader);
}
static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- auto* strokeShader = reinterpret_cast<Shader*>(strokeGradientPtr);
+ SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
path->mutateStagingProperties()->setStrokeGradient(strokeShader);
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 0eb4095..6bc318d 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -118,7 +118,7 @@
std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
std::string_view(fontPath.c_str(), fontPath.size()),
ttcIndex, builder->axes);
- minikin::Font font = minikin::Font::Builder(minikinFont).setWeight(weight)
+ std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
.setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
}
@@ -127,7 +127,7 @@
static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
jint weight, jboolean italic, jint ttcIndex) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
// Reconstruct SkTypeface with different arguments from existing SkTypeface.
@@ -148,8 +148,10 @@
minikinSkia->getFilePath(),
minikinSkia->GetFontIndex(),
builder->axes);
- minikin::Font newFont = minikin::Font::Builder(newMinikinFont).setWeight(weight)
- .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
+ std::shared_ptr<minikin::Font> newFont = minikin::Font::Builder(newMinikinFont)
+ .setWeight(weight)
+ .setSlant(static_cast<minikin::FontStyle::Slant>(italic))
+ .build();
return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
}
@@ -164,7 +166,7 @@
static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
jlong paintHandle, jobject rect) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
SkFont* skFont = &paint->getSkFont();
@@ -184,7 +186,7 @@
static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
jobject metricsObj) {
FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font->typeface().get());
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
SkFont* skFont = &paint->getSkFont();
@@ -200,11 +202,11 @@
// Critical Native
static jlong Font_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+ const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
- uint64_t result = font->font.style().weight();
- result |= font->font.style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
+ uint64_t result = font->style().weight();
+ result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
return result;
@@ -212,13 +214,19 @@
// Critical Native
static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+ const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+ MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
}
+// Critical Native
+static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+ return reinterpret_cast<jlong>(font->font.get());
+}
+
///////////////////////////////////////////////////////////////////////////////
struct FontBufferWrapper {
@@ -234,8 +242,8 @@
// Critical Native
static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- return reinterpret_cast<jlong>(new FontBufferWrapper(font->font.typeface()));
+ const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+ return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
}
// Fast Native
@@ -266,6 +274,7 @@
{ "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
{ "nGetFontInfo", "(J)J", (void*) Font_getFontInfo },
{ "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
+ { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
};
static const JNINativeMethod gFontBufferHelperMethods[] = {
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index df619d9..37e5276 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -30,7 +30,7 @@
namespace android {
struct NativeFamilyBuilder {
- std::vector<minikin::Font> fonts;
+ std::vector<std::shared_ptr<minikin::Font>> fonts;
};
static inline NativeFamilyBuilder* toBuilder(jlong ptr) {
diff --git a/libs/hwui/shader/BitmapShader.cpp b/libs/hwui/shader/BitmapShader.cpp
deleted file mode 100644
index fe653e8..0000000
--- a/libs/hwui/shader/BitmapShader.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BitmapShader.h"
-
-#include "SkImagePriv.h"
-
-namespace android::uirenderer {
-BitmapShader::BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
- const SkTileMode tileModeY, const SkMatrix* matrix)
- : Shader(matrix), skShader(image->makeShader(tileModeX, tileModeY)) {}
-
-sk_sp<SkShader> BitmapShader::makeSkShader() {
- return skShader;
-}
-
-BitmapShader::~BitmapShader() {}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/BitmapShader.h b/libs/hwui/shader/BitmapShader.h
deleted file mode 100644
index ed6a6e6..0000000
--- a/libs/hwui/shader/BitmapShader.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-/**
- * Shader implementation that renders a Bitmap as either a SkShader or SkImageFilter
- */
-class BitmapShader : public Shader {
-public:
- BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
- const SkTileMode tileModeY, const SkMatrix* matrix);
- ~BitmapShader() override;
-
-protected:
- sk_sp<SkShader> makeSkShader() override;
-
-private:
- sk_sp<SkShader> skShader;
-};
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/ComposeShader.cpp b/libs/hwui/shader/ComposeShader.cpp
deleted file mode 100644
index 3765489..0000000
--- a/libs/hwui/shader/ComposeShader.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ComposeShader.h"
-
-#include "SkImageFilters.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-ComposeShader::ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
- const SkMatrix* matrix)
- : Shader(matrix) {
- // If both Shaders can be represented as SkShaders then use those, if not
- // create an SkImageFilter from both Shaders and create the equivalent SkImageFilter
- sk_sp<SkShader> skShaderA = shaderA.asSkShader();
- sk_sp<SkShader> skShaderB = shaderB.asSkShader();
- if (skShaderA.get() && skShaderB.get()) {
- skShader = SkShaders::Blend(blendMode, skShaderA, skShaderB);
- skImageFilter = nullptr;
- } else {
- sk_sp<SkImageFilter> skImageFilterA = shaderA.asSkImageFilter();
- sk_sp<SkImageFilter> skImageFilterB = shaderB.asSkImageFilter();
- skShader = nullptr;
- skImageFilter = SkImageFilters::Xfermode(blendMode, skImageFilterA, skImageFilterB);
- }
-}
-
-sk_sp<SkShader> ComposeShader::makeSkShader() {
- return skShader;
-}
-
-sk_sp<SkImageFilter> ComposeShader::makeSkImageFilter() {
- return skImageFilter;
-}
-
-ComposeShader::~ComposeShader() {}
-} // namespace android::uirenderer
diff --git a/libs/hwui/shader/ComposeShader.h b/libs/hwui/shader/ComposeShader.h
deleted file mode 100644
index a246b52..0000000
--- a/libs/hwui/shader/ComposeShader.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-/**
- * Shader implementation that can composite 2 Shaders together with the specified blend mode.
- * This implementation can appropriately convert the composed result to either an SkShader or
- * SkImageFilter depending on the inputs
- */
-class ComposeShader : public Shader {
-public:
- ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
- const SkMatrix* matrix);
- ~ComposeShader() override;
-
-protected:
- sk_sp<SkShader> makeSkShader() override;
- sk_sp<SkImageFilter> makeSkImageFilter() override;
-
-private:
- sk_sp<SkShader> skShader;
- sk_sp<SkImageFilter> skImageFilter;
-};
-} // namespace android::uirenderer
diff --git a/libs/hwui/shader/LinearGradientShader.cpp b/libs/hwui/shader/LinearGradientShader.cpp
deleted file mode 100644
index 868fa44..0000000
--- a/libs/hwui/shader/LinearGradientShader.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LinearGradientShader.h"
-
-#include <vector>
-
-#include "SkGradientShader.h"
-
-namespace android::uirenderer {
-
-LinearGradientShader::LinearGradientShader(const SkPoint pts[2],
- const std::vector<SkColor4f>& colors,
- sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
- const SkTileMode tileMode, const uint32_t shaderFlags,
- const SkMatrix* matrix)
- : Shader(matrix)
- , skShader(SkGradientShader::MakeLinear(pts, colors.data(), colorspace, pos, colors.size(),
- tileMode, shaderFlags, nullptr)) {}
-
-sk_sp<SkShader> LinearGradientShader::makeSkShader() {
- return skShader;
-}
-
-LinearGradientShader::~LinearGradientShader() {}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/LinearGradientShader.h b/libs/hwui/shader/LinearGradientShader.h
deleted file mode 100644
index 596f4e0..0000000
--- a/libs/hwui/shader/LinearGradientShader.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-/**
- * Shader implementation that renders a color ramp of colors to either as either SkShader or
- * SkImageFilter
- */
-class LinearGradientShader : public Shader {
-public:
- LinearGradientShader(const SkPoint pts[2], const std::vector<SkColor4f>& colors,
- sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
- const SkTileMode tileMode, const uint32_t shaderFlags,
- const SkMatrix* matrix);
- ~LinearGradientShader() override;
-
-protected:
- sk_sp<SkShader> makeSkShader() override;
-
-private:
- sk_sp<SkShader> skShader;
-};
-} // namespace android::uirenderer
diff --git a/libs/hwui/shader/RadialGradientShader.cpp b/libs/hwui/shader/RadialGradientShader.cpp
deleted file mode 100644
index 21ff56f..0000000
--- a/libs/hwui/shader/RadialGradientShader.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "RadialGradientShader.h"
-
-#include <vector>
-
-#include "SkGradientShader.h"
-
-namespace android::uirenderer {
-
-RadialGradientShader::RadialGradientShader(const SkPoint& center, const float radius,
- const std::vector<SkColor4f>& colors,
- sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
- const SkTileMode tileMode, const uint32_t shaderFlags,
- const SkMatrix* matrix)
- : Shader(matrix)
- , skShader(SkGradientShader::MakeRadial(center, radius, colors.data(), colorspace, pos,
- colors.size(), tileMode, shaderFlags, nullptr)) {}
-
-sk_sp<SkShader> RadialGradientShader::makeSkShader() {
- return skShader;
-}
-
-RadialGradientShader::~RadialGradientShader() {}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RadialGradientShader.h b/libs/hwui/shader/RadialGradientShader.h
deleted file mode 100644
index 9a2ff13..0000000
--- a/libs/hwui/shader/RadialGradientShader.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-/**
- * Shader implementation that renders a color ramp from the center outward to either as either
- * a SkShader or SkImageFilter
- */
-class RadialGradientShader : public Shader {
-public:
- RadialGradientShader(const SkPoint& center, const float radius,
- const std::vector<SkColor4f>& colors, sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[], const SkTileMode tileMode, const uint32_t shaderFlags,
- const SkMatrix* matrix);
- ~RadialGradientShader() override;
-
-protected:
- sk_sp<SkShader> makeSkShader() override;
-
-private:
- sk_sp<SkShader> skShader;
-};
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.cpp b/libs/hwui/shader/RuntimeShader.cpp
deleted file mode 100644
index dd0b698..0000000
--- a/libs/hwui/shader/RuntimeShader.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RuntimeShader.h"
-
-#include "SkShader.h"
-#include "include/effects/SkRuntimeEffect.h"
-
-namespace android::uirenderer {
-
-RuntimeShader::RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
- const SkMatrix* matrix)
- : Shader(nullptr)
- , // Explicitly passing null as RuntimeShader is created with the
- // matrix directly
- skShader(effect.makeShader(std::move(data), nullptr, 0, matrix, isOpaque)) {}
-
-sk_sp<SkShader> RuntimeShader::makeSkShader() {
- return skShader;
-}
-
-RuntimeShader::~RuntimeShader() {}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.h b/libs/hwui/shader/RuntimeShader.h
deleted file mode 100644
index 7fe0b02..0000000
--- a/libs/hwui/shader/RuntimeShader.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-#include "include/effects/SkRuntimeEffect.h"
-
-namespace android::uirenderer {
-
-/**
- * RuntimeShader implementation that can map to either a SkShader or SkImageFilter
- */
-class RuntimeShader : public Shader {
-public:
- RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
- const SkMatrix* matrix);
- ~RuntimeShader() override;
-
-protected:
- sk_sp<SkShader> makeSkShader() override;
-
-private:
- sk_sp<SkShader> skShader;
-};
-} // namespace android::uirenderer
diff --git a/libs/hwui/shader/Shader.cpp b/libs/hwui/shader/Shader.cpp
deleted file mode 100644
index 45123dd..0000000
--- a/libs/hwui/shader/Shader.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Shader.h"
-
-#include "SkImageFilters.h"
-#include "SkPaint.h"
-#include "SkRefCnt.h"
-
-namespace android::uirenderer {
-
-Shader::Shader(const SkMatrix* matrix)
- : localMatrix(matrix ? *matrix : SkMatrix::I())
- , skShader(nullptr)
- , skImageFilter(nullptr) {}
-
-Shader::~Shader() {}
-
-sk_sp<SkShader> Shader::asSkShader() {
- // If we already have created a shader with these parameters just return the existing
- // shader we have already created
- if (!this->skShader.get()) {
- this->skShader = makeSkShader();
- if (this->skShader.get()) {
- if (!localMatrix.isIdentity()) {
- this->skShader = this->skShader->makeWithLocalMatrix(localMatrix);
- }
- }
- }
- return this->skShader;
-}
-
-/**
- * By default return null as we cannot convert all visual effects to SkShader instances
- */
-sk_sp<SkShader> Shader::makeSkShader() {
- return nullptr;
-}
-
-sk_sp<SkImageFilter> Shader::asSkImageFilter() {
- // If we already have created an ImageFilter with these parameters just return the existing
- // ImageFilter we have already created
- if (!this->skImageFilter.get()) {
- // Attempt to create an SkImageFilter from the current Shader implementation
- this->skImageFilter = makeSkImageFilter();
- if (this->skImageFilter) {
- if (!localMatrix.isIdentity()) {
- // If we have created an SkImageFilter and we have a transformation, wrap
- // the created SkImageFilter to apply the given matrix
- this->skImageFilter = SkImageFilters::MatrixTransform(
- localMatrix, kMedium_SkFilterQuality, this->skImageFilter);
- }
- } else {
- // Otherwise if no SkImageFilter implementation is provided, create one from
- // the result of asSkShader. Note the matrix is already applied to the shader in
- // this case so just convert it to an SkImageFilter using SkImageFilters::Paint
- SkPaint paint;
- paint.setShader(asSkShader());
- sk_sp<SkImageFilter> paintFilter = SkImageFilters::Paint(paint);
- this->skImageFilter = SkImageFilters::Xfermode(SkBlendMode::kDstIn,
- std::move(paintFilter));
- }
- }
- return this->skImageFilter;
-}
-
-/**
- * By default return null for subclasses to implement. If there is not a direct SkImageFilter
- * conversion
- */
-sk_sp<SkImageFilter> Shader::makeSkImageFilter() {
- return nullptr;
-}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/Shader.h b/libs/hwui/shader/Shader.h
deleted file mode 100644
index 6403e11..0000000
--- a/libs/hwui/shader/Shader.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "SkImageFilter.h"
-#include "SkShader.h"
-#include "SkPaint.h"
-#include "SkRefCnt.h"
-
-class SkMatrix;
-
-namespace android::uirenderer {
-
-/**
- * Shader class that can optionally wrap an SkShader or SkImageFilter depending
- * on the implementation
- */
-class Shader: public SkRefCnt {
-public:
- /**
- * Creates a Shader instance with an optional transformation matrix. The transformation matrix
- * is copied internally and ownership is unchanged. It is the responsibility of the caller to
- * deallocate it appropriately.
- * @param matrix Optional matrix to transform the underlying SkShader or SkImageFilter
- */
- Shader(const SkMatrix* matrix);
- virtual ~Shader();
-
- /**
- * Create an SkShader from the current Shader instance or return a previously
- * created instance. This can be null if no SkShader could be created from this
- * Shader instance.
- */
- sk_sp<SkShader> asSkShader();
-
- /**
- * Create an SkImageFilter from the current Shader instance or return a previously
- * created instance. Unlike asSkShader, this method cannot return null.
- */
- sk_sp<SkImageFilter> asSkImageFilter();
-
-protected:
- /**
- * Create a new SkShader instance based on this Shader instance
- */
- virtual sk_sp<SkShader> makeSkShader();
-
- /**
- * Create a new SkImageFilter instance based on this Shader instance. If no SkImageFilter
- * can be created then return nullptr
- */
- virtual sk_sp<SkImageFilter> makeSkImageFilter();
-
-private:
- /**
- * Optional matrix transform
- */
- const SkMatrix localMatrix;
-
- /**
- * Cached SkShader instance to be returned on subsequent queries
- */
- sk_sp<SkShader> skShader;
-
- /**
- * Cached SkImageFilter instance to be returned on subsequent queries
- */
- sk_sp<SkImageFilter> skImageFilter;
-};
-} // namespace android::uirenderer
diff --git a/libs/hwui/shader/SweepGradientShader.cpp b/libs/hwui/shader/SweepGradientShader.cpp
deleted file mode 100644
index 3b1f37f..0000000
--- a/libs/hwui/shader/SweepGradientShader.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SweepGradientShader.h"
-
-#include <vector>
-
-#include "SkGradientShader.h"
-#include "SkImageFilters.h"
-
-namespace android::uirenderer {
-
-SweepGradientShader::SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
- const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
- const uint32_t shaderFlags, const SkMatrix* matrix)
- : Shader(matrix)
- , skShader(SkGradientShader::MakeSweep(x, y, colors.data(), colorspace, pos, colors.size(),
- shaderFlags, nullptr)) {}
-
-sk_sp<SkShader> SweepGradientShader::makeSkShader() {
- return skShader;
-}
-
-SweepGradientShader::~SweepGradientShader() {}
-} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/SweepGradientShader.h b/libs/hwui/shader/SweepGradientShader.h
deleted file mode 100644
index dad3ef0..0000000
--- a/libs/hwui/shader/SweepGradientShader.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Shader.h"
-#include "SkShader.h"
-
-namespace android::uirenderer {
-
-/**
- * Shader implementation that renders a color ramp clockwise such that the start and end colors
- * are visible at 3 o'clock. This handles converting to either an SkShader or SkImageFilter
- */
-class SweepGradientShader : public Shader {
-public:
- SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
- const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
- const uint32_t shaderFlags, const SkMatrix* matrix);
- virtual ~SweepGradientShader() override;
-
-protected:
- virtual sk_sp<SkShader> makeSkShader() override;
-
-private:
- sk_sp<SkShader> skShader;
-};
-} // namespace android::uirenderer
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index e2c1651..c4067af 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -18,7 +18,6 @@
#include "hwui/Paint.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
-#include <shader/BitmapShader.h>
#include "utils/Color.h"
class BitmapShaders;
@@ -46,24 +45,15 @@
});
Paint paint;
- sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
- hwuiBitmap->makeImage(),
- SkTileMode::kRepeat,
- SkTileMode::kRepeat,
- nullptr
- );
-
sk_sp<SkImage> image = hwuiBitmap->makeImage();
- paint.setShader(std::move(bitmapShader));
+ sk_sp<SkShader> repeatShader =
+ image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
+ paint.setShader(std::move(repeatShader));
canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
- sk_sp<BitmapShader> mirrorBitmapShader = sk_make_sp<BitmapShader>(
- image,
- SkTileMode::kMirror,
- SkTileMode::kMirror,
- nullptr
- );
- paint.setShader(std::move(mirrorBitmapShader));
+ sk_sp<SkShader> mirrorShader =
+ image->makeShader(SkTileMode::kMirror, SkTileMode::kMirror);
+ paint.setShader(std::move(mirrorShader));
canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
}
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index d37bc3c..5886ea3 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -20,10 +20,6 @@
#include <SkGradientShader.h>
#include <SkImagePriv.h>
#include <ui/PixelFormat.h>
-#include <shader/BitmapShader.h>
-#include <shader/LinearGradientShader.h>
-#include <shader/RadialGradientShader.h>
-#include <shader/ComposeShader.h>
class HwBitmapInCompositeShader;
@@ -54,41 +50,20 @@
pixels[4000 + 4 * i + 3] = 255;
}
buffer->unlock();
-
- sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
- Bitmap::createFrom(
- buffer->toAHardwareBuffer(),
- SkColorSpace::MakeSRGB()
- )->makeImage(),
- SkTileMode::kClamp,
- SkTileMode::kClamp,
- nullptr
- );
+ sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer->toAHardwareBuffer(),
+ SkColorSpace::MakeSRGB()));
+ sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
SkPoint center;
center.set(50, 50);
+ SkColor colors[2];
+ colors[0] = Color::Black;
+ colors[1] = Color::White;
+ sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(
+ center, 50, colors, nullptr, 2, SkTileMode::kRepeat);
- std::vector<SkColor4f> vColors(2);
- vColors[0] = SkColors::kBlack;
- vColors[1] = SkColors::kWhite;
-
- sk_sp<RadialGradientShader> radialShader = sk_make_sp<RadialGradientShader>(
- center,
- 50,
- vColors,
- SkColorSpace::MakeSRGB(),
- nullptr,
- SkTileMode::kRepeat,
- 0,
- nullptr
- );
-
- sk_sp<ComposeShader> compositeShader = sk_make_sp<ComposeShader>(
- *bitmapShader.get(),
- *radialShader.get(),
- SkBlendMode::kDstATop,
- nullptr
- );
+ sk_sp<SkShader> compositeShader(
+ SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
Paint paint;
paint.setShader(std::move(compositeShader));
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index 76e39de..a9449b6 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -17,8 +17,7 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
#include "hwui/Paint.h"
-#include "SkColor.h"
-#include <shader/LinearGradientShader.h>
+#include <SkGradientShader.h>
class ListOfFadedTextAnimation;
@@ -43,26 +42,15 @@
pts[0].set(0, 0);
pts[1].set(0, 1);
+ SkColor colors[2] = {Color::Black, Color::Transparent};
+ sk_sp<SkShader> s(
+ SkGradientShader::MakeLinear(pts, colors, NULL, 2, SkTileMode::kClamp));
+
SkMatrix matrix;
matrix.setScale(1, length);
matrix.postRotate(-90);
-
- std::vector<SkColor4f> vColors(2);
- vColors[0] = SkColors::kBlack;
- vColors[1] = SkColors::kTransparent;
-
- sk_sp<LinearGradientShader> linearGradientShader = sk_make_sp<LinearGradientShader>(
- pts,
- vColors,
- SkColorSpace::MakeSRGB(),
- nullptr,
- SkTileMode::kClamp,
- 0,
- &matrix
- );
-
Paint fadingPaint;
- fadingPaint.setShader(linearGradientShader);
+ fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
fadingPaint.setBlendMode(SkBlendMode::kDstOut);
canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
canvas.restore();
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index bdc157f..a0bc5aa 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -17,7 +17,7 @@
#include "TestSceneBase.h"
#include <SkColorMatrixFilter.h>
-#include <shader/LinearGradientShader.h>
+#include <SkGradientShader.h>
class SimpleColorMatrixAnimation;
@@ -65,12 +65,9 @@
// enough renderer might apply it directly to the paint color)
float pos[] = {0, 1};
SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
- std::vector<SkColor4f> colors(2);
- colors[0] = SkColor4f::FromColor(Color::DeepPurple_500);
- colors[1] = SkColor4f::FromColor(Color::DeepOrange_500);
- paint.setShader(sk_make_sp<LinearGradientShader>(
- pts, colors, SkColorSpace::MakeSRGB(), pos, SkTileMode::kClamp,
- 0, nullptr));
+ SkColor colors[2] = {Color::DeepPurple_500, Color::DeepOrange_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+ SkTileMode::kClamp));
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 9a15c9d..57a260c 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -17,7 +17,6 @@
#include "TestSceneBase.h"
#include <SkGradientShader.h>
-#include <shader/LinearGradientShader.h>
class SimpleGradientAnimation;
@@ -56,24 +55,9 @@
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
// use i%2 start position to pick 2 color combo with black in it
- std::vector<SkColor4f> vColors(2);
- vColors[0] = ((i % 2) == 0) ?
- SkColor4f::FromColor(Color::Transparent) :
- SkColor4f::FromColor(Color::Black);
- vColors[1] = (((i + 1) % 2) == 0) ?
- SkColor4f::FromColor(Color::Black) :
- SkColor4f::FromColor(Color::Cyan_500);
-
- sk_sp<LinearGradientShader> gradient = sk_make_sp<LinearGradientShader>(
- pts,
- vColors,
- SkColorSpace::MakeSRGB(),
- pos,
- SkTileMode::kClamp,
- 0,
- nullptr
- );
- paint.setShader(gradient);
+ SkColor colors[3] = {Color::Transparent, Color::Black, Color::Cyan_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
+ SkTileMode::kClamp));
canvas.drawRect(i, i, width, height, paint);
}
});
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index b5baafd..5d2aa2f 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -59,7 +59,7 @@
std::shared_ptr<minikin::MinikinFont> font =
std::make_shared<MinikinFontSkia>(std::move(typeface), data, st.st_size, fileName, 0,
std::vector<minikin::FontVariation>());
- std::vector<minikin::Font> fonts;
+ std::vector<std::shared_ptr<minikin::Font>> fonts;
fonts.push_back(minikin::Font::Builder(font).build());
return std::make_shared<minikin::FontFamily>(std::move(fonts));
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 5e56b26..6d4c574 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,14 +17,9 @@
#include <gtest/gtest.h>
#include "PathParser.h"
-#include "GraphicsJNI.h"
-#include "SkGradientShader.h"
-#include "SkShader.h"
#include "VectorDrawable.h"
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
-#include <shader/Shader.h>
-#include <shader/LinearGradientShader.h>
#include <functional>
@@ -400,21 +395,7 @@
bitmap.allocN32Pixels(5, 5, false);
SkCanvas canvas(bitmap);
- SkPoint pts[2];
- pts[0].set(0, 0);
- pts[1].set(0, 0);
-
- std::vector<SkColor4f> colors(2);
- colors[0] = SkColors::kBlack;
- colors[1] = SkColors::kBlack;
-
- sk_sp<LinearGradientShader> shader = sk_sp(new LinearGradientShader(pts,
- colors,
- SkColorSpace::MakeSRGB(),
- nullptr,
- SkTileMode::kClamp,
- SkGradientShader::kInterpolateColorsInPremul_Flag,
- nullptr));
+ sk_sp<SkShader> shader = SkShaders::Color(SK_ColorBLACK);
// Initial ref count is 1
EXPECT_TRUE(shader->unique());
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 31dcd7e..5ae9dd2 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -46,7 +46,7 @@
*/
interface ILocationManager
{
- Location getLastLocation(String provider, String packageName, String attributionTag);
+ @nullable Location getLastLocation(String provider, String packageName, String attributionTag);
@nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 9aa0c87..46bd221 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -16,6 +16,8 @@
package android.location;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -586,6 +588,11 @@
}
/** @hide */
+ public long getElapsedRealtimeMillis() {
+ return NANOSECONDS.toMillis(getElapsedRealtimeNanos());
+ }
+
+ /** @hide */
public long getElapsedRealtimeAgeNanos(long referenceRealtimeNs) {
return referenceRealtimeNs - mElapsedRealtimeNanos;
}
@@ -595,6 +602,11 @@
return getElapsedRealtimeAgeNanos(SystemClock.elapsedRealtimeNanos());
}
+ /** @hide */
+ public long getElapsedRealtimeAgeMillis() {
+ return NANOSECONDS.toMillis(getElapsedRealtimeAgeNanos());
+ }
+
/**
* Set the time of this fix, in elapsed real-time since system boot.
*
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6e597b2..ff00409 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -89,6 +89,16 @@
public class LocationManager {
/**
+ * For apps targeting Android S and above, location clients may receive historical locations
+ * (from before the present time) under some circumstances.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ public static final long DELIVER_HISTORICAL_LOCATIONS = 73144566L;
+
+ /**
* For apps targeting Android R and above, {@link #getProvider(String)} will no longer throw any
* security exceptions.
*
@@ -1256,13 +1266,15 @@
* arguments. The same listener may be used across multiple providers with different requests
* for each provider.
*
- * <p>It may take a while to receive the first location update. If an immediate location is
- * required, applications may use the {@link #getLastKnownLocation(String)} method.
+ * <p>It may take some time to receive the first location update depending on the conditions the
+ * device finds itself in. In order to take advantage of cached locations, application may
+ * consider using {@link #getLastKnownLocation(String)} or {@link #getCurrentLocation(String,
+ * LocationRequest, CancellationSignal, Executor, Consumer)} instead.
*
* <p>See {@link LocationRequest} documentation for an explanation of various request parameters
* and how they can affect the received locations.
*
- * <p> If your application wants to passively observe location updates from any provider, then
+ * <p>If your application wants to passively observe location updates from all providers, then
* use the {@link #PASSIVE_PROVIDER}. This provider does not turn on or modify active location
* providers, so you do not need to be as careful about minimum time and minimum distance
* parameters. However, if your application performs heavy work on a location update (such as
@@ -1271,13 +1283,20 @@
*
* <p>In case the provider you have selected is disabled, location updates will cease, and a
* provider availability update will be sent. As soon as the provider is enabled again, another
- * provider availability update will be sent and location updates will immediately resume.
+ * provider availability update will be sent and location updates will resume.
*
- * <p> When location callbacks are invoked, the system will hold a wakelock on your
+ * <p>When location callbacks are invoked, the system will hold a wakelock on your
* application's behalf for some period of time, but not indefinitely. If your application
* requires a long running wakelock within the location callback, you should acquire it
* yourself.
*
+ * <p>Spamming location requests is a drain on system resources, and the system has preventative
+ * measures in place to ensure that this behavior will never result in more locations than could
+ * be achieved with a single location request with an equivalent interval that is left in place
+ * the whole time. As part of this amelioration, applications that target Android S and above
+ * may receive cached or historical locations through their listener. These locations will never
+ * be older than the interval of the location request.
+ *
* <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
*
* @param provider a provider listed by {@link #getAllProviders()}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 0521b10..3bb4781 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -27,6 +27,8 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -45,6 +47,17 @@
public final class LocationRequest implements Parcelable {
/**
+ * For apps targeting Android S and above, all LocationRequest objects marked as low power will
+ * throw exceptions if the caller does not have the LOCATION_HARDWARE permission, instead of
+ * silently dropping the low power part of the request.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ public static final long LOW_POWER_EXCEPTIONS = 168936375L;
+
+ /**
* Represents a passive only request. Such a request will not trigger any active locations or
* power usage itself, but may receive locations generated in response to other requests.
*
@@ -737,7 +750,7 @@
s.append(qualityToString(mQuality)).append(" ");
}
if (mInterval != PASSIVE_INTERVAL) {
- s.append("interval=");
+ s.append("@");
TimeUtils.formatDuration(mInterval, s);
} else {
s.append("PASSIVE");
@@ -752,7 +765,8 @@
if (mMaxUpdates != Integer.MAX_VALUE) {
s.append(" maxUpdates=").append(mMaxUpdates);
}
- if (mMinUpdateIntervalMillis < mInterval) {
+ if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL
+ && mMinUpdateIntervalMillis < mInterval) {
s.append(" minUpdateInterval=");
TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
}
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 24dacc4..3af2e17 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -472,7 +472,8 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(publicAlternatives = "Check equality of {@link #getSessionToken() tokens}"
+ + "instead.")
public boolean controlsSameSession(MediaController other) {
if (other == null) return false;
return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
diff --git a/media/java/android/media/tv/TvChannelInfo.java b/media/java/android/media/tv/TvChannelInfo.java
index 635b130..11cb1f7 100644
--- a/media/java/android/media/tv/TvChannelInfo.java
+++ b/media/java/android/media/tv/TvChannelInfo.java
@@ -22,19 +22,44 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
/**
+ * This class is used to specify information of a TV channel.
* @hide
*/
public final class TvChannelInfo implements Parcelable {
static final String TAG = "TvChannelInfo";
+
+ /**
+ * App tag for {@link #getAppTag()}: the corresponding application of the channel is the same as
+ * the caller.
+ * <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
+ * {@link #APP_TAG_SELF}.
+ */
public static final int APP_TAG_SELF = 0;
+ /**
+ * App tag for {@link #getAppType()}: the corresponding application of the channel is the same
+ * as the caller.
+ * <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
+ * {@link #APP_TAG_SELF}.
+ */
public static final int APP_TYPE_SELF = 1;
+ /**
+ * App tag for {@link #getAppType()}: the corresponding app of the channel is a system
+ * application.
+ */
public static final int APP_TYPE_SYSTEM = 2;
+ /**
+ * App tag for {@link #getAppType()}: the corresponding app of the channel is not a system
+ * application.
+ */
public static final int APP_TYPE_NON_SYSTEM = 3;
/** @hide */
@@ -68,6 +93,7 @@
@AppType private final int mAppType;
private final int mAppTag;
+ /** @hide */
public TvChannelInfo(
String inputId, @Nullable Uri channelUri, boolean isRecordingSession,
boolean isForeground, @AppType int appType, int appTag) {
@@ -90,24 +116,41 @@
mAppTag = source.readInt();
}
+ /**
+ * Returns the TV input ID of the channel.
+ */
+ @NonNull
public String getInputId() {
return mInputId;
}
+ /**
+ * Returns the channel URI of the channel.
+ * <p>Returns {@code null} if it's a passthrough input or the permission is not granted.
+ */
+ @Nullable
public Uri getChannelUri() {
return mChannelUri;
}
+ /**
+ * Returns {@code true} if the channel session is a recording session.
+ * @see TvInputService.RecordingSession
+ */
public boolean isRecordingSession() {
return mIsRecordingSession;
}
+ /**
+ * Returns {@code true} if the application is a foreground application.
+ * @see android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+ */
public boolean isForeground() {
return mIsForeground;
}
/**
- * Gets app tag.
+ * Returns the app tag.
* <p>App tag is used to differentiate one app from another.
* {@link #APP_TAG_SELF} is for current app.
*/
@@ -115,6 +158,9 @@
return mAppTag;
}
+ /**
+ * Returns the app type.
+ */
@AppType
public int getAppType() {
return mAppType;
@@ -126,7 +172,7 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mInputId);
String uriString = mChannelUri == null ? null : mChannelUri.toString();
dest.writeString(uriString);
@@ -145,4 +191,26 @@
+ ";appType=" + mAppType
+ ";appTag=" + mAppTag;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TvChannelInfo)) {
+ return false;
+ }
+
+ TvChannelInfo other = (TvChannelInfo) o;
+
+ return TextUtils.equals(mInputId, other.getInputId())
+ && Objects.equals(mChannelUri, other.mChannelUri)
+ && mIsRecordingSession == other.mIsRecordingSession
+ && mIsForeground == other.mIsForeground
+ && mAppType == other.mAppType
+ && mAppTag == other.mAppTag;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mInputId, mChannelUri, mIsRecordingSession, mIsForeground, mAppType, mAppTag);
+ }
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d38369f..c80f3c6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -900,8 +900,13 @@
public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
}
- /** @hide */
- public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) {
+ /**
+ * This is called when the information about current TV channels has been updated.
+ *
+ * @param tvChannelInfos a list of {@link TvChannelInfo} objects of new current channels.
+ * @hide
+ */
+ public void onCurrentTvChannelInfosUpdated(@NonNull List<TvChannelInfo> tvChannelInfos) {
}
}
@@ -1976,8 +1981,15 @@
}
/**
+ * Returns the list of TV channel information for {@link TvInputService.Session} that are
+ * currently in use.
+ * <p> Permission com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS is required to get
+ * the channel URIs. If the permission is not granted, {@link TvChannelInfo#getChannelUri()}
+ * returns {@code null}.
* @hide
*/
+ @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
+ @NonNull
public List<TvChannelInfo> getCurrentTvChannelInfos() {
try {
return mService.getCurrentTvChannelInfos(mUserId);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 1e9cf2c..4e27c8e 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -95,6 +95,11 @@
"-Wunused",
"-Wunreachable-code",
],
+
+ // Workaround Clang LTO crash.
+ lto: {
+ never: true,
+ },
}
cc_library_shared {
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 5ba5c01..40e4c54 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -28,4 +28,9 @@
"-Wunused",
"-Wunreachable-code",
],
+
+ // Workaround Clang LTO crash.
+ lto: {
+ never: true,
+ },
}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 0af6cbf..0a466f4 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -317,10 +317,9 @@
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
sp<SurfaceControl> newParentSurfaceControl = ASurfaceControl_to_SurfaceControl(
newParentASurfaceControl);
- sp<IBinder> newParentHandle = (newParentSurfaceControl)? newParentSurfaceControl->getHandle() : nullptr;
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
- transaction->reparent(surfaceControl, newParentHandle);
+ transaction->reparent(surfaceControl, newParentSurfaceControl);
}
void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction,
diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp
index 4037781..00b9019 100644
--- a/non-updatable-api/Android.bp
+++ b/non-updatable-api/Android.bp
@@ -23,13 +23,31 @@
}
filegroup {
+ name: "non-updatable-removed.txt",
+ srcs: ["removed.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
name: "non-updatable-system-current.txt",
srcs: ["system-current.txt"],
visibility: ["//frameworks/base/api"],
}
filegroup {
+ name: "non-updatable-system-removed.txt",
+ srcs: ["system-removed.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
name: "non-updatable-module-lib-current.txt",
srcs: ["module-lib-current.txt"],
visibility: ["//frameworks/base/api"],
}
+
+filegroup {
+ name: "non-updatable-module-lib-removed.txt",
+ srcs: ["module-lib-removed.txt"],
+ visibility: ["//frameworks/base/api"],
+}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 4d0a01c..983f20a 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -21,6 +21,7 @@
field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+ field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -129,6 +130,7 @@
field public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
field public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+ field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
@@ -644,10 +646,10 @@
field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
- field public static final int fontProviderAuthority = 16844112; // 0x1010550
- field public static final int fontProviderCerts = 16844125; // 0x101055d
- field public static final int fontProviderPackage = 16844119; // 0x1010557
- field public static final int fontProviderQuery = 16844113; // 0x1010551
+ field @Deprecated public static final int fontProviderAuthority = 16844112; // 0x1010550
+ field @Deprecated public static final int fontProviderCerts = 16844125; // 0x101055d
+ field @Deprecated public static final int fontProviderPackage = 16844119; // 0x1010557
+ field @Deprecated public static final int fontProviderQuery = 16844113; // 0x1010551
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontVariationSettings = 16844144; // 0x1010570
field public static final int fontWeight = 16844083; // 0x1010533
@@ -12235,6 +12237,7 @@
field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
+ field public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 8; // 0x8
field public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 2; // 0x2
field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1
field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4
@@ -12344,6 +12347,7 @@
field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4
field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10
field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
+ field public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 32; // 0x20
field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8
field public static final int PROTECTION_DANGEROUS = 1; // 0x1
field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
@@ -35206,7 +35210,7 @@
method public int dataCapacity();
method public int dataPosition();
method public int dataSize();
- method public void enforceInterface(String);
+ method public void enforceInterface(@NonNull String);
method public boolean hasFileDescriptors();
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
@@ -35277,7 +35281,7 @@
method public void writeFloatArray(@Nullable float[]);
method public void writeInt(int);
method public void writeIntArray(@Nullable int[]);
- method public void writeInterfaceToken(String);
+ method public void writeInterfaceToken(@NonNull String);
method public void writeList(@Nullable java.util.List);
method public void writeLong(long);
method public void writeLongArray(@Nullable long[]);
@@ -38721,62 +38725,62 @@
method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
}
- public final class FontRequest {
- ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String);
- ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
- method public java.util.List<java.util.List<byte[]>> getCertificates();
- method public String getProviderAuthority();
- method public String getProviderPackage();
- method public String getQuery();
+ @Deprecated public final class FontRequest {
+ ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String);
+ ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
+ method @Deprecated public java.util.List<java.util.List<byte[]>> getCertificates();
+ method @Deprecated public String getProviderAuthority();
+ method @Deprecated public String getProviderPackage();
+ method @Deprecated public String getQuery();
}
- public class FontsContract {
- method public static android.graphics.Typeface buildTypeface(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontInfo[]);
- method @NonNull public static android.provider.FontsContract.FontFamilyResult fetchFonts(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
- method public static void requestFonts(@NonNull android.content.Context, @NonNull android.provider.FontRequest, @NonNull android.os.Handler, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontRequestCallback);
+ @Deprecated public class FontsContract {
+ method @Deprecated public static android.graphics.Typeface buildTypeface(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontInfo[]);
+ method @Deprecated @NonNull public static android.provider.FontsContract.FontFamilyResult fetchFonts(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public static void requestFonts(@NonNull android.content.Context, @NonNull android.provider.FontRequest, @NonNull android.os.Handler, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontRequestCallback);
}
- public static final class FontsContract.Columns implements android.provider.BaseColumns {
- field public static final String FILE_ID = "file_id";
- field public static final String ITALIC = "font_italic";
- field public static final String RESULT_CODE = "result_code";
- field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
- field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
- field public static final int RESULT_CODE_OK = 0; // 0x0
- field public static final String TTC_INDEX = "font_ttc_index";
- field public static final String VARIATION_SETTINGS = "font_variation_settings";
- field public static final String WEIGHT = "font_weight";
+ @Deprecated public static final class FontsContract.Columns implements android.provider.BaseColumns {
+ field @Deprecated public static final String FILE_ID = "file_id";
+ field @Deprecated public static final String ITALIC = "font_italic";
+ field @Deprecated public static final String RESULT_CODE = "result_code";
+ field @Deprecated public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field @Deprecated public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field @Deprecated public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field @Deprecated public static final int RESULT_CODE_OK = 0; // 0x0
+ field @Deprecated public static final String TTC_INDEX = "font_ttc_index";
+ field @Deprecated public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field @Deprecated public static final String WEIGHT = "font_weight";
}
- public static class FontsContract.FontFamilyResult {
- method @NonNull public android.provider.FontsContract.FontInfo[] getFonts();
- method public int getStatusCode();
- field public static final int STATUS_OK = 0; // 0x0
- field public static final int STATUS_REJECTED = 3; // 0x3
- field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
- field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ @Deprecated public static class FontsContract.FontFamilyResult {
+ method @Deprecated @NonNull public android.provider.FontsContract.FontInfo[] getFonts();
+ method @Deprecated public int getStatusCode();
+ field @Deprecated public static final int STATUS_OK = 0; // 0x0
+ field @Deprecated public static final int STATUS_REJECTED = 3; // 0x3
+ field @Deprecated public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field @Deprecated public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
}
- public static class FontsContract.FontInfo {
- method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
- method public int getResultCode();
- method @IntRange(from=0) public int getTtcIndex();
- method @NonNull public android.net.Uri getUri();
- method @IntRange(from=1, to=1000) public int getWeight();
- method public boolean isItalic();
+ @Deprecated public static class FontsContract.FontInfo {
+ method @Deprecated @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
+ method @Deprecated public int getResultCode();
+ method @Deprecated @IntRange(from=0) public int getTtcIndex();
+ method @Deprecated @NonNull public android.net.Uri getUri();
+ method @Deprecated @IntRange(from=1, to=1000) public int getWeight();
+ method @Deprecated public boolean isItalic();
}
- public static class FontsContract.FontRequestCallback {
- ctor public FontsContract.FontRequestCallback();
- method public void onTypefaceRequestFailed(int);
- method public void onTypefaceRetrieved(android.graphics.Typeface);
- field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
- field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
- field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
- field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
- field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ @Deprecated public static class FontsContract.FontRequestCallback {
+ ctor @Deprecated public FontsContract.FontRequestCallback();
+ method @Deprecated public void onTypefaceRequestFailed(int);
+ method @Deprecated public void onTypefaceRetrieved(android.graphics.Typeface);
+ field @Deprecated public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field @Deprecated public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field @Deprecated public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field @Deprecated public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field @Deprecated public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field @Deprecated public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
}
@Deprecated public final class LiveFolders implements android.provider.BaseColumns {
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 11cd6a9..003a363 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -19,7 +19,7 @@
package android.app.role {
public final class RoleManager {
- method @Nullable public String getDefaultSmsPackage(int);
+ method @Nullable public String getSmsRoleHolder(int);
}
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 916e21f..04847d5 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -95,6 +95,7 @@
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
+ field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
@@ -125,6 +126,7 @@
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+ field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -305,6 +307,7 @@
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
+ field public static final int config_systemVideoCall = 17039401; // 0x1040029
}
public static final class R.style {
@@ -1329,6 +1332,57 @@
}
+package android.app.time {
+
+ public final class TimeManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void removeTimeZoneDetectorListener(@NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public boolean updateTimeZoneConfiguration(@NonNull android.app.time.TimeZoneConfiguration);
+ }
+
+ @java.lang.FunctionalInterface public static interface TimeManager.TimeZoneDetectorListener {
+ method public void onChange();
+ }
+
+ public final class TimeZoneCapabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConfigureAutoDetectionEnabledCapability();
+ method public int getConfigureGeoDetectionEnabledCapability();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
+ field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
+ field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
+ field public static final int CAPABILITY_POSSESSED = 40; // 0x28
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
+ }
+
+ public final class TimeZoneCapabilitiesAndConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.app.time.TimeZoneCapabilities getCapabilities();
+ method @NonNull public android.app.time.TimeZoneConfiguration getConfiguration();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilitiesAndConfig> CREATOR;
+ }
+
+ public final class TimeZoneConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isAutoDetectionEnabled();
+ method public boolean isGeoDetectionEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneConfiguration> CREATOR;
+ }
+
+ public static final class TimeZoneConfiguration.Builder {
+ ctor public TimeZoneConfiguration.Builder();
+ ctor public TimeZoneConfiguration.Builder(@NonNull android.app.time.TimeZoneConfiguration);
+ method @NonNull public android.app.time.TimeZoneConfiguration build();
+ method @NonNull public android.app.time.TimeZoneConfiguration.Builder setAutoDetectionEnabled(boolean);
+ method @NonNull public android.app.time.TimeZoneConfiguration.Builder setGeoDetectionEnabled(boolean);
+ }
+
+}
+
package android.app.usage {
public final class CacheQuotaHint implements android.os.Parcelable {
@@ -2097,6 +2151,7 @@
field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
+ field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
@@ -9580,16 +9635,12 @@
method public int getTimeoutSeconds();
method public boolean isEnabled();
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
- field public static final int ERROR_FDN_CHECK_FAILURE = 2; // 0x2
- field public static final int ERROR_NOT_SUPPORTED = 3; // 0x3
- field public static final int ERROR_UNKNOWN = 1; // 0x1
field public static final int REASON_ALL = 4; // 0x4
field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
field public static final int REASON_BUSY = 1; // 0x1
field public static final int REASON_NOT_REACHABLE = 3; // 0x3
field public static final int REASON_NO_REPLY = 2; // 0x2
field public static final int REASON_UNCONDITIONAL = 0; // 0x0
- field public static final int SUCCESS = 0; // 0x0
}
public final class CallQuality implements android.os.Parcelable {
@@ -10275,6 +10326,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
@@ -10332,7 +10384,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingStatus(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
@@ -10431,6 +10483,10 @@
public static interface TelephonyManager.CallForwardingInfoCallback {
method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo);
method public void onError(int);
+ field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 2; // 0x2
+ field public static final int RESULT_ERROR_NOT_SUPPORTED = 3; // 0x3
+ field public static final int RESULT_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 0; // 0x0
}
public final class UiccAccessRule implements android.os.Parcelable {
@@ -11797,11 +11853,12 @@
}
public interface PacProcessor {
+ method @NonNull public static android.webkit.PacProcessor createInstance();
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
+ method public default void setNetwork(@Nullable android.net.Network);
method public boolean setProxyScript(@NonNull String);
}
@@ -11937,11 +11994,11 @@
}
public interface WebViewFactoryProvider {
+ method @NonNull public default android.webkit.PacProcessor createPacProcessor();
method public android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml b/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml
index 1b12eb4..51d2b9d 100644
--- a/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml
+++ b/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml
@@ -14,9 +14,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/system_bar_background_pill_color"/>
- <corners android:radius="30dp"/>
-</shape>
\ No newline at end of file
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <item>
+ <aapt:attr name="android:drawable">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/system_bar_background_pill_color"/>
+ <corners android:radius="30dp"/>
+ </shape>
+ </aapt:attr>
+ </item>
+ <item>
+ <aapt:attr name="android:drawable">
+ <ripple android:color="?android:attr/colorControlHighlight"/>
+ </aapt:attr>
+ </item>
+</layer-list>
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index f242db0..f5de2fd 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -49,5 +49,6 @@
<item name="android:padding">@dimen/system_bar_button_padding</item>
<item name="android:gravity">center</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="unselectedAlpha">0.56</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/Android.bp b/packages/CarSystemUI/samples/sample2/rro/Android.bp
new file mode 100644
index 0000000..bf68e41
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/Android.bp
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+
+android_app {
+ name: "CarSystemUISampleTwoRRO",
+ resource_dirs: ["res"],
+ certificate: "platform",
+ platform_apis: true,
+ manifest: "AndroidManifest.xml",
+ aaptflags: [
+ "--no-resource-deduping",
+ "--no-resource-removal",
+ ]
+}
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml b/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml
new file mode 100644
index 0000000..5c25056
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.rro">
+ <overlay
+ android:targetPackage="com.android.systemui"
+ android:isStatic="false"
+ android:resourcesMap="@xml/car_sysui_overlays"
+ />
+</manifest>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml
new file mode 100644
index 0000000..a8d8a2f
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="44"
+ android:viewportHeight="44"
+ android:width="44dp"
+ android:height="44dp">
+<path
+ android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml
new file mode 100644
index 0000000..6339ebb
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="44"
+ android:viewportHeight="44"
+ android:width="44dp"
+ android:height="44dp">
+ <path
+ android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml
new file mode 100644
index 0000000..e1fabe0
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="44"
+ android:viewportHeight="44"
+ android:width="44dp"
+ android:height="44dp">
+ <path
+ android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml
new file mode 100644
index 0000000..3c3fefc
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="44dp"
+ android:height="44dp"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
+ <path
+ android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml
new file mode 100644
index 0000000..f185eb9
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="44"
+ android:viewportHeight="44"
+ android:width="44dp"
+ android:height="44dp">
+ <path
+ android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
+ android:strokeColor="@color/car_nav_icon_fill_color"
+ android:strokeWidth="4" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml
new file mode 100644
index 0000000..50e36b5
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="44"
+ android:viewportHeight="44"
+ android:width="44dp"
+ android:height="44dp">
+ <path
+ android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml
new file mode 100644
index 0000000..6161ad9
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
+ <corners
+ android:topLeftRadius="0dp"
+ android:topRightRadius="10dp"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp"
+ />
+ <solid
+ android:color="#404040"
+ />
+ <padding
+ android:left="0dp"
+ android:top="0dp"
+ android:right="0dp"
+ android:bottom="0dp"
+ />
+</shape>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml
new file mode 100644
index 0000000..bd6065c
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml
@@ -0,0 +1,105 @@
+<?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.
+*/
+-->
+
+<com.android.systemui.car.navigationbar.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:background="@drawable/system_bar_background">
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/home"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
+ systemui:icon="@drawable/car_ic_overview"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
+ systemui:highlightWhenSelected="true"
+ />
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/maps_nav"
+ style="@style/NavigationBarButton"
+ systemui:categories="android.intent.category.APP_MAPS"
+ systemui:icon="@drawable/car_ic_navigation"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
+ systemui:highlightWhenSelected="true"
+ />
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/music_nav"
+ style="@style/NavigationBarButton"
+ systemui:categories="android.intent.category.APP_MUSIC"
+ systemui:icon="@drawable/car_ic_music"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
+ systemui:packages="com.android.car.media"
+ systemui:highlightWhenSelected="true"
+ />
+
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/grid_nav"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
+ systemui:icon="@drawable/car_ic_apps"
+ systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
+ systemui:highlightWhenSelected="true"
+ />
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/phone_nav"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_phone"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
+ systemui:packages="com.android.car.dialer"
+ systemui:highlightWhenSelected="true"
+ />
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/notifications"
+ style="@style/NavigationBarButton"
+ systemui:highlightWhenSelected="true"
+ systemui:icon="@drawable/car_ic_notification"
+ systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="bottom"
+ android:orientation="vertical">
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:singleLine="true"
+ android:gravity="center_horizontal"
+ android:paddingBottom="20dp"
+ />
+
+ <Space
+ android:layout_height="10dp"
+ android:layout_width="match_parent"/>
+
+ </LinearLayout>
+
+</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml
new file mode 100644
index 0000000..7ba3334
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <attr name="broadcast" format="boolean"/>
+ <attr name="icon" format="reference"/>
+ <attr name="selectedIcon" format="reference"/>
+ <attr name="intent" format="string"/>
+ <attr name="longIntent" format="string"/>
+ <attr name="componentNames" format="string" />
+ <attr name="highlightWhenSelected" format="boolean" />
+ <attr name="categories" format="string"/>
+ <attr name="packages" format="string" />
+</resources>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml
new file mode 100644
index 0000000..c32d638
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="car_nav_icon_fill_color">#8F8F8F</color>
+ <color name="car_nav_icon_fill_color_selected">#FFFFFF</color>
+</resources>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml
new file mode 100644
index 0000000..89c7bd4
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <!-- Configure which system bars should be displayed. -->
+ <bool name="config_enableTopNavigationBar">false</bool>
+ <bool name="config_enableLeftNavigationBar">true</bool>
+ <bool name="config_enableRightNavigationBar">false</bool>
+ <bool name="config_enableBottomNavigationBar">false</bool>
+
+ <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
+ <!-- STATUS_BAR = 0-->
+ <!-- NAVIGATION_BAR = 1-->
+ <!-- STATUS_BAR_EXTRA = 2-->
+ <!-- NAVIGATION_BAR_EXTRA = 3-->
+ <integer name="config_topSystemBarType">0</integer>
+ <integer name="config_leftSystemBarType">1</integer>
+ <integer name="config_rightSystemBarType">2</integer>
+ <integer name="config_bottomSystemBarType">3</integer>
+
+ <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
+ if both top bar and left bar are enabled, it creates an overlapping space in the upper left
+ corner), the system bar with the higher z-order takes the overlapping space and padding is
+ applied to the other bar.-->
+ <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
+ RuntimeException, since their placing order cannot be determined. Bars that do not overlap
+ are allowed to have the same z-order. -->
+ <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
+ <integer name="config_topSystemBarZOrder">0</integer>
+ <integer name="config_leftSystemBarZOrder">10</integer>
+ <integer name="config_rightSystemBarZOrder">10</integer>
+ <integer name="config_bottomSystemBarZOrder">10</integer>
+
+ <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
+ notifications will be shown pushed to the top of their parent container. If true, they will
+ be shown pushed to the bottom of their parent container. If true, then should override
+ config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
+ com.android.car.notification.headsup.animationhelper.
+ CarHeadsUpNotificationBottomAnimationHelper. -->
+ <bool name="config_showHeadsUpNotificationOnBottom">true</bool>
+
+ <string name="config_notificationPanelViewMediator" translatable="false">com.android.systemui.car.notification.NotificationPanelViewMediator</string>
+</resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml
new file mode 100644
index 0000000..136dc3b
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="TextAppearance.StatusBar.Clock"
+ parent="@*android:style/TextAppearance.StatusBar.Icon">
+ <item name="android:textSize">40sp</item>
+ <item name="android:fontFamily">sans-serif-regular</item>
+ <item name="android:textColor">#FFFFFF</item>
+ </style>
+
+ <style name="NavigationBarButton">
+ <item name="android:layout_height">96dp</item>
+ <item name="android:layout_width">96dp</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">30sp</item>
+ <item name="android:textColor">#FFFFFF</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml
new file mode 100644
index 0000000..58a535b
--- /dev/null
+++ b/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml
@@ -0,0 +1,66 @@
+
+<!--
+ ~ 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.
+ -->
+
+<overlay>
+ <item target="layout/car_left_navigation_bar" value="@layout/car_left_navigation_bar"/>
+
+ <item target="attr/icon" value="@attr/icon"/>
+ <item target="attr/selectedIcon" value="@attr/selectedIcon"/>
+ <item target="attr/intent" value="@attr/intent"/>
+ <item target="attr/longIntent" value="@attr/longIntent"/>
+ <item target="attr/componentNames" value="@attr/componentNames"/>
+ <item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
+ <item target="attr/categories" value="@attr/categories"/>
+ <item target="attr/packages" value="@attr/packages"/>
+ <!-- start the intent as a broad cast instead of an activity if true-->
+ <item target="attr/broadcast" value="@attr/broadcast"/>
+
+ <item target="drawable/car_ic_overview" value="@drawable/car_ic_overview" />
+ <item target="drawable/car_ic_apps" value="@drawable/car_ic_apps" />
+ <item target="drawable/car_ic_music" value="@drawable/car_ic_music" />
+ <item target="drawable/car_ic_phone" value="@drawable/car_ic_phone" />
+ <item target="drawable/car_ic_navigation" value="@drawable/car_ic_navigation" />
+
+ <item target="style/NavigationBarButton" value="@style/NavigationBarButton"/>
+
+ <item target="color/car_nav_icon_fill_color" value="@color/car_nav_icon_fill_color" />
+
+ <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/>
+ <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/>
+ <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/>
+ <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/>
+ <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom"/>
+
+ <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/>
+ <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/>
+ <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/>
+ <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/>
+
+ <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/>
+ <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/>
+ <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/>
+ <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/>
+
+ <item target="string/config_notificationPanelViewMediator" value="@string/config_notificationPanelViewMediator"/>
+
+ <item target="id/home" value="@id/home"/>
+ <item target="id/maps_nav" value="@id/maps_nav"/>
+ <item target="id/music_nav" value="@id/music_nav"/>
+ <item target="id/grid_nav" value="@id/grid_nav"/>
+ <item target="id/phone_nav" value="@id/phone_nav"/>
+ <item target="id/notifications" value="@id/notifications"/>
+</overlay>
\ No newline at end of file
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index e05bd3c..d3aa977 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -21,8 +21,6 @@
import static androidx.test.ext.truth.location.LocationSubject.assertThat;
-import static com.google.common.truth.Truth.assertThat;
-
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bc66601..506b608 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -764,6 +764,9 @@
Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST);
dumpSetting(s, p,
+ Settings.Global.ANGLE_EGL_FEATURES,
+ GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
+ dumpSetting(s, p,
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
dumpSetting(s, p,
@@ -889,9 +892,6 @@
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
GlobalSettingsProto.Location.SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
dumpSetting(s, p,
- Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
- GlobalSettingsProto.Location.GLOBAL_KILL_SWITCH);
- dumpSetting(s, p,
Settings.Global.GNSS_SATELLITE_BLACKLIST,
GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3ccb1f4..710c016 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -328,10 +328,6 @@
return SettingsState.getUserIdFromKey(key);
}
- public static String settingTypeToString(int type) {
- return SettingsState.settingTypeToString(type);
- }
-
public static String keyToString(int key) {
return SettingsState.keyToString(key);
}
@@ -373,8 +369,7 @@
}
case Settings.CALL_METHOD_GET_SECURE: {
- Setting setting = getSecureSetting(name, requestingUserId,
- /*enableOverride=*/ true);
+ Setting setting = getSecureSetting(name, requestingUserId);
return packageValueForCallResult(setting, isTrackingGeneration(args));
}
@@ -581,7 +576,7 @@
}
private ArrayList<String> buildSettingsList(Cursor cursor) {
- final ArrayList<String> lines = new ArrayList<String>();
+ final ArrayList<String> lines = new ArrayList<>();
try {
while (cursor != null && cursor.moveToNext()) {
lines.add(cursor.getString(1) + "=" + cursor.getString(2));
@@ -1381,10 +1376,6 @@
}
private Setting getSecureSetting(String name, int requestingUserId) {
- return getSecureSetting(name, requestingUserId, /*enableOverride=*/ false);
- }
-
- private Setting getSecureSetting(String name, int requestingUserId, boolean enableOverride) {
if (DEBUG) {
Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
}
@@ -1414,14 +1405,6 @@
return getSsaidSettingLocked(callingPkg, owningUserId);
}
}
- if (enableOverride) {
- if (Secure.LOCATION_MODE.equals(name)) {
- final Setting overridden = getLocationModeSetting(owningUserId);
- if (overridden != null) {
- return overridden;
- }
- }
- }
// Not the SSAID; do a straight lookup
synchronized (mLock) {
@@ -1511,35 +1494,6 @@
return null;
}
- private Setting getLocationModeSetting(int owningUserId) {
- synchronized (mLock) {
- final Setting setting = getGlobalSetting(
- Global.LOCATION_GLOBAL_KILL_SWITCH);
- if (!"1".equals(setting.getValue())) {
- return null;
- }
- // Global kill-switch is enabled. Return an empty value.
- final SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
- SETTINGS_TYPE_SECURE, owningUserId);
- return settingsState.new Setting(
- Secure.LOCATION_MODE,
- "", // value
- "", // tag
- "", // default value
- "", // package name
- false, // from system
- "0" // id
- ) {
- @Override
- public boolean update(String value, boolean setDefault, String packageName,
- String tag, boolean forceNonSystemPackage, boolean overrideableByRestore) {
- Slog.wtf(LOG_TAG, "update shouldn't be called on this instance.");
- return false;
- }
- };
- }
- }
-
private boolean insertSecureSetting(String name, String value, String tag,
boolean makeDefault, int requestingUserId, boolean forceNotify,
boolean overrideableByRestore) {
@@ -1808,12 +1762,8 @@
private boolean hasWriteSecureSettingsPermission() {
// Write secure settings is a more protected permission. If caller has it we are good.
- if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
-
- return false;
+ return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
}
private void validateSystemSettingValue(String name, String value) {
@@ -3174,12 +3124,6 @@
if (isGlobalSettingsKey(key) || isConfigSettingsKey(key)) {
final long token = Binder.clearCallingIdentity();
try {
- if (Global.LOCATION_GLOBAL_KILL_SWITCH.equals(name)
- && isGlobalSettingsKey(key)) {
- // When the global kill switch is updated, send the
- // change notification for the location setting.
- notifyLocationChangeForRunningUsers();
- }
notifySettingChangeForRunningUsers(key, name);
} finally {
Binder.restoreCallingIdentity(token);
@@ -3257,26 +3201,6 @@
}
}
- private void notifyLocationChangeForRunningUsers() {
- final List<UserInfo> users = mUserManager.getAliveUsers();
-
- for (int i = 0; i < users.size(); i++) {
- final int userId = users.get(i).id;
-
- if (!mUserManager.isUserRunning(UserHandle.of(userId))) {
- continue;
- }
-
- // Increment the generation first, so observers always see the new value
- final int key = makeKey(SETTINGS_TYPE_SECURE, userId);
- mGenerationRegistry.incrementGeneration(key);
-
- final Uri uri = getNotificationUriFor(key, Secure.LOCATION_MODE);
- mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
- userId, 0, uri).sendToTarget();
- }
- }
-
private boolean isConfigSettingsKey(int key) {
return getTypeFromKey(key) == SETTINGS_TYPE_CONFIG;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 6678cf6..b061df1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -34,7 +34,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.Global;
import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -47,7 +46,6 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import libcore.io.IoUtils;
@@ -817,13 +815,6 @@
for (int i = 0; i < settingCount; i++) {
Setting setting = settings.valueAt(i);
- if (setting.isTransient()) {
- if (DEBUG_PERSISTENCE) {
- Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName());
- }
- continue;
- }
-
writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
setting.getTag(), setting.isDefaultFromSystem(),
@@ -1109,8 +1100,7 @@
ATTR_DEFAULT_VALUE_BASE64);
String isPreservedInRestoreString = parser.getAttributeValue(null,
ATTR_PRESERVE_IN_RESTORE);
- boolean isPreservedInRestore = isPreservedInRestoreString != null
- && Boolean.parseBoolean(isPreservedInRestoreString);
+ boolean isPreservedInRestore = Boolean.parseBoolean(isPreservedInRestoreString);
String tag = null;
boolean fromSystem = false;
if (defaultValue != null) {
@@ -1308,14 +1298,6 @@
/* resetToDefault */ true);
}
- public boolean isTransient() {
- switch (getTypeFromKey(getKey())) {
- case SETTINGS_TYPE_GLOBAL:
- return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName());
- }
- return false;
- }
-
public boolean update(String value, boolean setDefault, String packageName, String tag,
boolean forceNonSystemPackage, boolean overrideableByRestore) {
return update(value, setDefault, packageName, tag, forceNonSystemPackage,
@@ -1444,7 +1426,7 @@
}
private static String fromBytes(byte[] bytes) {
- final StringBuffer sb = new StringBuffer(bytes.length / 2);
+ final StringBuilder sb = new StringBuilder(bytes.length / 2);
final int last = bytes.length - 1;
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 0810979..e027fd3 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -503,6 +503,7 @@
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
+ Settings.Global.ANGLE_EGL_FEATURES,
Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f5f58ef..a927997 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -326,6 +326,9 @@
<!-- Permission needed for CTS test - DisplayTest -->
<uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" />
+ <!-- Permission needed for CTS test - TimeManagerTest -->
+ <uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index cf78a13..505ef7a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -518,7 +518,7 @@
<!-- started from PipController -->
<activity
- android:name=".pip.tv.PipMenuActivity"
+ android:name="com.android.wm.shell.pip.tv.PipMenuActivity"
android:permission="com.android.systemui.permission.SELF"
android:exported="false"
android:theme="@style/PipTheme"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 72dfe74..7d3390d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Instellings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vergrotingvensterkontroles"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Voeg kontroles vir jou gekoppelde toestelle by"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Stel toestelkontroles op"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ontkoppel)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kon nie koppel nie. Probeer weer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0ec236d..a91182e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ቅንብሮች"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"የማጉያ መስኮት መቆጣጠሪያዎች"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ለእርስዎ የተገናኙ መሣሪያዎች መቆጣጠሪያዎችን ያክሉ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"የመሣሪያ መቆጣጠሪያዎችን ያቀናብሩ"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ግንኙነት ተቋርጧል)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ማገናኘት አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b09e5b9..74a9b64 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1032,6 +1032,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"الإعدادات"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"عناصر التحكم في نافذة التكبير"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"إضافة عناصر تحكّم لأجهزتك المتصلة"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"إعداد أدوات التحكم بالجهاز"</string>
@@ -1049,7 +1061,7 @@
<string name="accessibility_control_favorite" msgid="8694362691985545985">"تمت الإضافة إلى المفضّلة"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"تمت الإضافة إلى المفضّلة، الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"تمت الإزالة من المفضّلة"</string>
- <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"إضافة إلى المُفضلة"</string>
+ <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"إضافة إلى المحتوى المفضّل"</string>
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"إزالة من المفضّلة"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"نقل إلى الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"عناصر التحكّم"</string>
@@ -1099,4 +1111,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (غير متّصل)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"تعذّر الاتصال. يُرجى إعادة المحاولة."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 61ba6dc..297d774 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ছেটিংসমূহ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"বিবৰ্ধন ৱিণ্ড’ৰ নিয়ন্ত্ৰণসমূহ"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"আপোনাৰ সংযোজিত ডিভাইচসমূহৰ বাবে নিয়ন্ত্ৰণসমূহ যোগ কৰক"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (সংযোগ বিচ্ছিন্ন হৈছে)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"সংযোগ কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰক।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index bee0e5f..debad02 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ayarlar"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Böyütmə Pəncərəsi Kontrolları"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz idarəetmələri"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Qoşulmuş cihazlarınız üçün nizamlayıcılar əlavə edin"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz idarəetmələrini ayarlayın"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (bağlantı kəsilib)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Qoşulmaq alınmadı. Yenə cəhd edin."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihazı qoşalaşdırın"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 5966356..be31c2d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Podešavanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećanje"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Podesite kontrole uređaja"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index cedc375..e3831a8 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налады"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Налады акна павелічэння"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Дадайце элементы кіравання для падключаных прылад"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Наладзіць элементы кіравання прыладай"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (адключана)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не ўдалося падключыцца. Паўтарыце спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1408840..d959178 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за ниво на мащаба"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли за прозореца за ниво на мащаба"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавяне на контроли за свързаните ви устройства"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройване на контролите за устройството"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (връзката е прекратена)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Неуспешно свързване. Опитайте отново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index aed9522..fffa555 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"সেটিংস"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"আপনার কানেক্ট করা ডিভাইসের জন্য কন্ট্রোল যোগ করুন"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইস কন্ট্রোল সেট-আপ করুন"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (কানেক্ট করা নেই)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"কানেক্ট করা যায়নি। আবার চেষ্টা করুন।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 41a2671..f5410cf 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećavanje"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspjelo. Pokušajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0a03680..28bf3bb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuració"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra de controls d\'ampliació"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Afegeix controls per als teus dispositius connectats"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura els controls de dispositius"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconnectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No s\'ha pogut connectar. Torna-ho a provar."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 419e625..c66f200 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavení"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládací prvky zvětšovacího okna"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Přidejte ovládací prvky pro připojená zařízení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavení ovládání zařízení"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (odpojeno)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Spojení se nezdařilo. Zkuste to znovu."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f2e8a3f..5b0566d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Indstillinger"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vindue med forstørrelsesstyring"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj styring af dine tilsluttede enheder"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhedsstyring"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ingen forbindelse)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Der kunne ikke oprettes forbindelse. Prøv igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4dbd74a..0ab1f0e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Einstellungen"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Einstellungen für Vergrößerungsfenster"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Steuerelemente für verbundene Geräte hinzufügen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Gerätesteuerung einrichten"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nicht verbunden)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Verbindung nicht möglich. Versuch es noch einmal."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1b912c7..6d86e91 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ρυθμίσεις"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Στοιχεία ελέγχου παραθύρου μεγέθυνσης"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Προσθήκη στοιχείων ελέγχου για τις συνδεδεμένες συσκευές σας."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Ρύθμιση στοιχείων ελέγχου συσκευής"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (αποσυνδέθηκε)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Δεν ήταν δυνατή η σύνδεση. Δοκιμάστε ξανά."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 065c17b..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 1cc6625..8e5849e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 065c17b..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 065c17b..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 7702337..e107ed5 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification Window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification Window Controls"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8a8f1e7..be37623 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Agrega controles para los dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles de dispositivos"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se pudo establecer la conexión. Vuelve a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 20b50ab..08b17cc 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ajustes"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ventana de controles de ampliación"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles para tus dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se ha podido conectar. Inténtalo de nuevo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular nuevo dispositivo"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ced0604..b33ad01 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Seaded"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurendamisakna juhtelemendid"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadmete juhtimisvidinate seadistamine"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (pole ühendatud)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ühenduse loomine ebaõnnestus. Proovige uuesti."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index e8d2f47..3f1a53c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ezarpenak"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Gehitu konektatutako gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguratu gailuak kontrolatzeko widgetak"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (deskonektatuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ezin izan da konektatu. Saiatu berriro."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f6cf179..e5606a2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -246,7 +246,7 @@
<string name="accessibility_remove_notification" msgid="1641455251495815527">"پاک کردن اعلان"</string>
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS فعال شد."</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"دستیابی به GPS."</string>
- <string name="accessibility_tty_enabled" msgid="1123180388823381118">"TeleTypewriter فعال شد."</string>
+ <string name="accessibility_tty_enabled" msgid="1123180388823381118">"تلهتایپ فعال شد."</string>
<string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"زنگ لرزشی."</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"زنگ بیصدا."</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"تنظیمات"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگنمایی"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"کنترلهای پنجره بزرگنمایی"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"افزودن کنترلها برای دستگاههای متصل"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"تنظیم کنترلهای دستگاه"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (اتصال قطع شد)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"متصل نشد. دوباره امتحان کنید."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3d9a6db..e00b50e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Asetukset"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurennusikkunan ohjaimet"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisää ohjaimia yhdistettyjä laitteita varten"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Laitteiden hallinnan käyttöönotto"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (yhteys katkaistu)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ei yhteyttä. Yritä uudelleen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ff89ce2..03e205d 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a126cfa..82df63a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Fenêtre des commandes d\'agrandissement"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9075a69..9be451d 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -246,7 +246,7 @@
<string name="accessibility_remove_notification" msgid="1641455251495815527">"Eliminar notificación."</string>
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS activado"</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"Obtendo GPS."</string>
- <string name="accessibility_tty_enabled" msgid="1123180388823381118">"TeleTypewriter activado"</string>
+ <string name="accessibility_tty_enabled" msgid="1123180388823381118">"Teletipo activado"</string>
<string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"Timbre en vibración"</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"Timbre silenciado"</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controis de ampliación da ventá"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Engade controis para os dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar o control de dispositivos"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (dispositivo desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Non se puido establecer a conexión. Téntao de novo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e8b4460..864d05f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"સેટિંગ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"તમારા કનેક્ટ કરેલા ડિવાઇસ માટે નિયંત્રણો ઉમેરો"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ડિવાઇસનાં નિયંત્રણો સેટઅપ કરો"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ડિસ્કનેક્ટ થયેલું)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"કનેક્ટ કરી શકાયું નહીં. ફરી પ્રયાસ કરો."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 9a563d9..e11055c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1014,6 +1014,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिंग"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"स्क्रीन को बड़ा करके दिखाने वाली विंडो के नियंत्रण"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"कनेक्ट किए गए डिवाइस के लिए कंट्रोल जोड़ें"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"डिवाइस कंट्रोल सेट अप करें"</string>
@@ -1077,4 +1089,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिसकनेक्ट किया गया)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट नहीं किया जा सका. फिर से कोशिश करें."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 649299b..d5033fa 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za povećavanje"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavljanje kontrola uređaja"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nije povezano)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije bilo moguće. Pokušajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f658bb7..6d960e7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Beállítások"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Nagyítási vezérlők ablaka"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Vezérlők hozzáadása a csatlakoztatott eszközökhöz"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Eszközvezérlők beállítása"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (leválasztva)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Sikertelen csatlakozás. Próbálja újra."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 171773c..9e746fa 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -246,7 +246,7 @@
<string name="accessibility_remove_notification" msgid="1641455251495815527">"Մաքրել ծանուցումը:"</string>
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS-ը միացված է:"</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"GPS-ի ստացում:"</string>
- <string name="accessibility_tty_enabled" msgid="1123180388823381118">"Հեռամուտքագրիչը միացված է:"</string>
+ <string name="accessibility_tty_enabled" msgid="1123180388823381118">"Հեռատիպը միացված է:"</string>
<string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"Թրթռազանգ:"</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"Զանգակը լռեցված է:"</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Կարգավորումներ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Խոշորացման պատուհանի կառավարման տարրեր"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ավելացրեք կառավարման տարրեր ձեր միացված սարքերի համար"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Սարքերի կառավարման տարրերի կարգավորում"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (անջատված է)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Չհաջողվեց միանալ։ Նորից փորձեք։"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 12f42e8..380e943 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -597,7 +597,7 @@
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Ringkasan untuk melepas pin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Beranda untuk melepas pin."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang dipasangi pin dapat membuka aplikasi lain."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang disematkan dapat membuka aplikasi lain."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk melepas pin aplikasi ini, sentuh & lama tombol Kembali dan Ringkasan"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas pin aplikasi ini, sentuh & lama tombol Kembali dan Layar utama"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk melepas pin aplikasi ini, geser ke atas & tahan"</string>
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setelan"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrol Jendela Pembesaran"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambahkan kontrol untuk perangkat terhubung"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Siapkan kontrol perangkat"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (terputus)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak dapat terhubung. Coba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 4a750a5..dd12ed6 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Stillingar"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Stækkunarstillingar glugga"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bæta við stýringum fyrir tengd tæki"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Setja upp tækjastjórnun"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (aftengt)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tenging mistókst. Reyndu aftur."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index eb76a4b..851228f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Impostazioni"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra controlli di ingrandimento"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Aggiungi controlli per i dispositivi connessi"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura il controllo dei dispositivi"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnesso)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossibile connettersi. Riprova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e6fbdb5..d4ad45e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"הגדרות"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"יש להוסיף פקדים למכשירים המחוברים"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"הגדרה של פקדי מכשירים"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (מנותק)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"לא ניתן היה להתחבר. יש לנסות שוב."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b358f3d..7547853 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"拡大ウィンドウ コントロール"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"接続済みデバイスのコントロールを追加します"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"デバイス コントロールの設定"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(未接続)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"接続できませんでした。もう一度お試しください。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4e85d60..69b1d14 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"პარამეტრები"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"გადიდების კონტროლის ფანჯარა"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"მოწყობილ. მართვის საშუალებები"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"მართვის საშუალებების დამატება თქვენს დაკავშირებულ მოწყობილობებზე"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"მოწყობილობის მართვის საშუალებების დაყენება"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (კავშირი გაწყვეტილია)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"დაკავშირება ვერ მოხერხდა. ცადეთ ხელახლა."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index f172106..b86f32e 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Параметрлер"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ұлғайту терезесінің басқару элементтері"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғылар үшін басқару виджеттерін қосу"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ажыратылған)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Қосылмады. Қайта қосылып көріңіз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғыны жұптау"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index b126a11..e895140 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ការកំណត់"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"វិនដូការពង្រីក"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"វិនដូគ្រប់គ្រងការពង្រីក"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូលផ្ទាំងគ្រប់គ្រងសម្រាប់ឧបករណ៍ដែលអ្នកបានភ្ជាប់"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (បានផ្ដាច់)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"មិនអាចភ្ជាប់បានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 475677b..2a9f649 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ನಿಮ್ಮ ಸಂಪರ್ಕಿತ ಸಾಧನಗಳಿಗೆ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೆಟಪ್ ಮಾಡಿ"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ac7f04e..559205c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"설정"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가하세요."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(연결 끊김)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"연결할 수 없습니다. 다시 시도하세요."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index b1fab07..a688150 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Жөндөөлөр"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланышкан түзмөктөрүңүздү башкаруу элементтерин кошосуз"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Түзмөктү башкаруу элементтерин жөндөө"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ажыратылды)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Байланышпай койду. Кайталоо."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 67642d3..1a6c338 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ການຕັ້ງຄ່າ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ການຄວບຄຸມໜ້າຈໍການຂະຫຍາຍ"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ເພີ່ມການຄວບຄຸມສຳລັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ແລ້ວຂອງທ່ານ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ຕັ້ງຄ່າການຄວບຄຸມອຸປະກອນ"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້. ລອງໃໝ່."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index e17f6e4..6fb84dd8 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1022,6 +1022,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nustatymai"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Didinimo lango valdikliai"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Artinti"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Tolinti"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Perkelti aukštyn"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Perkelti žemyn"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Perkelti kairėn"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Perkelti dešinėn"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridėkite prijungtų įrenginių valdiklių"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Įrenginio valdiklių nustatymas"</string>
@@ -1087,4 +1093,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"„<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ (atjungta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepavyko prijungti. Bandykite dar kartą."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 96d563c..9864a61 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Iestatījumi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Palielināšanas loga vadīklas"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Ierīču vadīklas"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pievienojiet vadīklas pievienotajām ierīcēm"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Ierīču vadīklu iestatīšana"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (savienojums pārtraukts)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nevarēja izveidot savienojumu. Mēģiniet vēlreiz."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f53147e..362cbdc 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Поставки"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли на прозорец за зголемување"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроли за поврзаните уреди"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Поставете ги контролите за уредите"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (исклучен)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не можеше да се поврзе. Обидете се повторно."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 80f0106..95634b8 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ക്രമീകരണം"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ നിയന്ത്രണങ്ങൾ"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"കണക്റ്റ് ചെയ്ത ഉപകരണങ്ങൾക്ക് നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ഉപകരണ നിയന്ത്രണങ്ങൾ സജ്ജീകരിക്കുക"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (വിച്ഛേദിച്ചു)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"കണക്റ്റ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 1c82e48..a2e1745 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Тохиргоо"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Томруулалтын цонхны хяналт"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Холбогдсон төхөөрөмжүүд дээрээ хяналт нэмэх"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Төхөөрөмжийн хяналтыг тохируулах"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (салсан)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Холбогдож чадсангүй. Дахин оролдоно уу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b26f89f..7a62c17 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिंग्ज"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"मॅग्निफिकेशन विंडो नियंत्रणे"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"तुमच्या कनेक्ट केलेल्या डिव्हाइससाठी नियंत्रणे जोडा"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"डिव्हाइस नियंत्रणे सेट करा"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिस्कनेक्ट केले)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट करू शकलो नाही. पुन्हा प्रयत्न करा."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 92bc807..2b501bb 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Tetapan"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kawalan Tetingkap Pembesaran"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambah kawalan untuk peranti yang disambungkan"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Sediakan kawalan peranti"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (diputuskan sambungan)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak boleh menyambung. Cuba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9cc9398..1cbf17fe 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ဆက်တင်များ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ဝင်းဒိုး ထိန်းချုပ်မှုများ ချဲ့ခြင်း"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ချိတ်ဆက်စက်များအတွက် ထိန်းချုပ်မှုများထည့်ပါ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"စက်ထိန်းစနစ် ထည့်သွင်းခြင်း"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ချိတ်ဆက်မထားပါ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ချိတ်ဆက်၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 92ae689..6d6d66f 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Innstillinger"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontroller for forstørringsvindu"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Legg til kontroller for de tilkoblede enhetene dine"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhetsstyring"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (frakoblet)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kunne ikke koble til. Prøv på nytt."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 1346874..e1dd8c0 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिङ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"म्याग्निफिकेसन विन्डोका नियन्त्रणहरू"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"यन्त्र नियन्त्रण गर्ने विजेटहरू"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"आफ्ना जोडिएका यन्त्रहरूका लागि नियन्त्रण सुविधाहरू थप्नुहोस्"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"यन्त्र नियन्त्रण गर्ने विजेटहरू सेटअप गर्नुहोस्"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिस्कनेक्ट गरिएको)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ यन्त्रको जोडा बनाउनुहोस्"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 139b57b..e2db22c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Instellingen"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Bediening van vergrotingsvenster"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bedieningselementen voor je gekoppelde apparaten toevoegen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Apparaatbediening instellen"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (verbinding verbroken)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kan geen verbinding maken. Probeer het nog eens."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3973734..970e61c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ସେଟିଂସ୍"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ଆପଣଙ୍କ ସଂଯୁକ୍ତ ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣ ଯୋଗ କରନ୍ତୁ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index e727f48a..690d6e5b 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ਸੈਟਿੰਗਾਂ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window ਦੇ ਕੰਟਰੋਲ"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ਆਪਣੇ ਕਨੈਕਟ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਲਈ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ਡਿਸਕਨੈਕਟ ਹੋਇਆ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f188aaa..9b31c52 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ustawienia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Elementy sterujące okna powiększenia"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące połączonymi urządzeniami"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurowanie sterowania urządzeniami"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (rozłączono)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nie udało się połączyć. Spróbuj ponownie."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8c8adae..b76ebda 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Aumentar zoom"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Diminuir zoom"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Mover para cima"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 082e14e..089bbd4 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Definições"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controlos da janela de ampliação"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adicione controlos para os dispositivos associados."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configure os controlos de dispositivos"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desligado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível ligar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8c8adae..b76ebda 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1012,6 +1012,12 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
+ <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Aumentar zoom"</string>
+ <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Diminuir zoom"</string>
+ <string name="accessibility_control_move_up" msgid="6622825494014720136">"Mover para cima"</string>
+ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
+ <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
+ <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
@@ -1075,4 +1081,6 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 4128c21..3194b9f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setări"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Comenzi pentru fereastra de mărire"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adăugați comenzi pentru dispozitivele conectate"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurați comenzile dispozitivelor"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (s-a deconectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nu s-a putut conecta. Reîncercați."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7584173..26e3433 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Настройки окна увеличения"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавьте виджеты для управления устройствами."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройте виджеты управления устройствами"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (отключено)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не удалось подключиться. Повторите попытку."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 98e8d1f..8eea1ed 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"සැකසීම්"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"විශාලනය කිරීමේ කවුළු පාලන"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ඔබේ සම්බන්ධිත උපාංග සඳහා පාලන එක් කරන්න"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"උපාංග පාලන පිහිටුවන්න"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (විසන්ධි විය)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"සම්බන්ධ වීමට නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d9c6279..47045d8 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavenia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládacie prvky okna priblíženia"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte si ovládače pripojených zariadení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (odpojené)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepodarilo sa pripojiť. Skúste to znova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 778938c..7b68a3a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavitve"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrolniki povečevalnega okna"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrolnike za povezane naprave"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavitev kontrolnikov naprave"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (povezava prekinjena)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezave ni bilo mogoče vzpostaviti. Poskusite znova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 5172303..b7ebb2a 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -246,7 +246,7 @@
<string name="accessibility_remove_notification" msgid="1641455251495815527">"Pastro njoftimin."</string>
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS-ja është e aktivizuar."</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"Po siguron GPS-në."</string>
- <string name="accessibility_tty_enabled" msgid="1123180388823381118">"Teleprinteri është i aktivizuar."</string>
+ <string name="accessibility_tty_enabled" msgid="1123180388823381118">"Teletajpi është i aktivizuar."</string>
<string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"Zile me dridhje."</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"Zilja është heshtur."</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cilësimet"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrollet e dritares së zmadhimit"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Shto kontrolle për pajisjet e tua të lidhura"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguro kontrollet e pajisjes"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (e shkëputur)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nuk mund të lidhej. Provo sërish."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 90f1c5a..b6a90cd 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1017,6 +1017,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Подешавања"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроле прозора за увећање"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроле за повезане уређаје"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Подесите контроле уређаја"</string>
@@ -1081,4 +1093,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (веза је прекинута)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Повезивање није успело. Пробајте поново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8918f51..890f504 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Inställningar"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Inställningar för förstoringsfönster"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lägg till snabbkontroller för anslutna enheter"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurera enhetsstyrning"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (frånkopplad)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Det gick inte att ansluta. Försök igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3949f2d..34042ad 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Mipangilio"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vidhibiti vya Dirisha la Ukuzaji"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa ulivyounganisha"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Weka mipangilio ya vidhibiti vya vifaa"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (hakijaunganishwa)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Imeshindwa kuunganisha. Jaribu tena."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index d91f1fd..b30859f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -879,12 +879,12 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"குறைந்த முன்னுரிமை உள்ள அறிவிப்பு ஐகான்களைக் காட்டு"</string>
<string name="other" msgid="429768510980739978">"மற்றவை"</string>
- <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"டைலை அகற்றும்"</string>
- <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"கடைசியில் டைலைச் சேர்க்கும்"</string>
- <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"டைலை நகர்த்து"</string>
- <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"டைலைச் சேர்"</string>
- <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> இடத்திற்கு நகர்த்தும்"</string>
- <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> என்ற இடத்தில் சேர்க்கும்"</string>
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"கட்டத்தை அகற்றும்"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"கடைசியில் கட்டத்தைச் சேர்க்கும்"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"கட்டத்தை நகர்த்து"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"கட்டத்தைச் சேர்"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>க்கு நகர்த்தும்"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>ல் சேர்க்கும்"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"இடம்: <xliff:g id="POSITION">%1$d</xliff:g>"</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>
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"அமைப்புகள்"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"பெரிதாக்கல் சாளரக் கட்டுப்பாடுகள்"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"இணைக்கப்பட்ட சாதனங்களில் கட்டுப்பாடுகளைச் சேர்க்கலாம்"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"சாதனக் கட்டுப்பாடுகளை அமைத்தல்"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (இணைப்பு துண்டிக்கப்பட்டது)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"இணைக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d7a27b8..cb134a1 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"సెట్టింగ్లు"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"మాగ్నిఫికేషన్ నియంత్రణల విండో"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"పరికరం నియంత్రణలు"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"మీ కనెక్ట్ అయిన పరికరాలకు నియంత్రణలను జోడించండి"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"పరికరం నియంత్రణలను సెటప్ చేయడం"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (డిస్కనెక్ట్ అయ్యింది)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"కనెక్ట్ చేయడం సాధ్యపడలేదు. మళ్లీ ట్రై చేయండి."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index cb6089f..d678353 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"การตั้งค่า"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"การควบคุมหน้าต่างการขยาย"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"เพิ่มตัวควบคุมของอุปกรณ์ที่เชื่อมต่อ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ตั้งค่าระบบควบคุมอุปกรณ์"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ยกเลิกการเชื่อมต่อแล้ว)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"เชื่อมต่อไม่ได้ ลองใหม่"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7e6aa62..21fdd31 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Mga Setting"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Mga Kontrol sa Pag-magnify ng Window"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Magdagdag ng kontrol para sa mga nakakonektang device"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"I-set up ang mga kontrol ng device"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nakadiskonekta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Hindi makakonekta. Subukan ulit."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index dac352f..3e04d19 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ayarlar"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Büyütme Penceresi Kontrolleri"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bağlı cihazlarınız için denetimler ekleyin"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz denetimlerini kur"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (bağlı değil)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Bağlanılamadı. Tekrar deneyin."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 26053af..a7c6bef 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1022,6 +1022,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налаштування"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Елементи керування вікна збільшення"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додайте елементи керування для підключених пристроїв"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Налаштувати елементи керування пристроями"</string>
@@ -1087,4 +1099,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (відключено)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не вдалося підключитися. Повторіть спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4bd192f..f24492c 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ترتیبات"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"اپنے منسلک آلات کے لیے کنٹرولز شامل کریں"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"آلہ کے کنٹرولز سیٹ اپ کریں"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (غیر منسلک ہو گیا)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"منسلک نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7c3728a..32c2406 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Sozlamalar"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kattalashtirish oynasi sozlamalari"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalar uchun boshqaruv elementlari"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (uzilgan)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ulanmadi. Qayta urining."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f23f742..d9c80df 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cài đặt"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Các tùy chọn điều khiển cửa sổ phóng to"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Thêm các tùy chọn điều khiển cho các thiết bị đã kết nối của bạn"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Thiết lập các tùy chọn điều khiển thiết bị"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (đã ngắt kết nối)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Không thể kết nối. Hãy thử lại."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9b81cb0..9f9424d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"设置"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大窗口控件"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"为您所连接的设备添加控件"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控件"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(已断开连接)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"无法连接。请重试。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index dbb9e03..2825a9e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"為連接的裝置新增控制選項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4e4db70..8acf2c6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"新增已連結裝置的控制項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 65e9a1c..4935206 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1012,6 +1012,18 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Amasethingi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Izilawuli Zewindi Lesikhulisi"</string>
+ <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
+ <skip />
+ <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
+ <skip />
+ <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
+ <skip />
<string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Engeza izilawuli zedivayisi yakho exhunyiwe"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Setha izilawuli zezinsiza"</string>
@@ -1075,4 +1087,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (inqamukile)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ayikwazanga ukuxhumeka. Zama futhi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhanqa idivayisi entsha"</string>
+ <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
+ <skip />
+ <!-- no translation found for build_number_copy_toast (877720921605503046) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
index 7451ba8..2e77674 100644
--- a/packages/SystemUI/res/values/config_tv.xml
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -15,10 +15,6 @@
-->
<resources>
- <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
- when the PIP menu is shown in center. -->
- <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
-
<!-- Whether to enable microphone disclosure indicator
(com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar). -->
<bool name="audio_recording_disclosure_enabled">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8777d50..7cbbaf9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -974,8 +974,6 @@
<!-- The start margin of quick scrub onboarding toast. -->
<dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
- <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
-
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
@@ -1232,8 +1230,6 @@
<dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
<dimen name="bubble_manage_menu_elevation">4dp</dimen>
- <dimen name="dismiss_target_x_size">24dp</dimen>
-
<!-- Bubbles user education views -->
<dimen name="bubbles_manage_education_width">160dp</dimen>
<!-- The inset from the top bound of the manage button to place the user education. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4ba757f..2427d360 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2829,4 +2829,9 @@
<string name="media_output_dialog_connect_failed">Couldn\'t connect. Try again.</string>
<!-- Title for pairing item [CHAR LIMIT=60] -->
<string name="media_output_dialog_pairing_new">Pair new device</string>
+
+ <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
+ <string name="build_number_clip_data_label">Build number</string>
+ <!-- Text to display when copying the build number off QS [CHAR LIMIT=NONE]-->
+ <string name="build_number_copy_toast">Build number copied to clipboard.</string>
</resources>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 68f4b746..606fd2c 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -37,8 +37,6 @@
static_libs: [
"PluginCoreLib",
],
-
-
java_version: "1.8",
min_sdk_version: "26",
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index ee05c6c..a98f666 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -34,7 +34,6 @@
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
-import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.ContentResolver;
import android.content.Context;
@@ -43,7 +42,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -228,21 +226,10 @@
/**
* Starts the recents activity. The caller should manage the thread on which this is called.
*/
- public void startRecentsActivity(Intent intent, final AssistDataReceiver assistDataReceiver,
+ public void startRecentsActivity(Intent intent, long eventTime,
final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
try {
- IAssistDataReceiver receiver = null;
- if (assistDataReceiver != null) {
- receiver = new IAssistDataReceiver.Stub() {
- public void onHandleAssistData(Bundle resultData) {
- assistDataReceiver.onHandleAssistData(resultData);
- }
- public void onHandleAssistScreenshot(Bitmap screenshot) {
- assistDataReceiver.onHandleAssistScreenshot(screenshot);
- }
- };
- }
IRecentsAnimationRunner runner = null;
if (animationHandler != null) {
runner = new IRecentsAnimationRunner.Stub() {
@@ -272,7 +259,7 @@
}
};
}
- ActivityTaskManager.getService().startRecentsActivity(intent, receiver, runner);
+ ActivityTaskManager.getService().startRecentsActivity(intent, eventTime, runner);
if (resultCallback != null) {
resultCallbackHandler.post(new Runnable() {
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index 345a649..0db4faf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -86,4 +86,12 @@
opts.setFreezeRecentTasksReordering();
return opts;
}
+
+ /**
+ * Sets the launch event time from launcher.
+ */
+ public static ActivityOptions setLauncherSourceInfo(ActivityOptions opts, long uptimeMillis) {
+ opts.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, uptimeMillis);
+ return opts;
+ }
}
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 aed7c21..a1c1f93 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
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import android.app.PictureInPictureParams;
import android.app.WindowConfiguration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -49,6 +50,7 @@
public final Rect screenSpaceBounds;
public final boolean isNotInRecents;
public final Rect contentInsets;
+ public final PictureInPictureParams pictureInPictureParams;
private final SurfaceControl mStartLeash;
@@ -66,6 +68,7 @@
isNotInRecents = app.isNotInRecents;
contentInsets = app.contentInsets;
activityType = app.windowConfiguration.getActivityType();
+ pictureInPictureParams = app.pictureInPictureParams;
mStartLeash = app.startLeash;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 76090f8..bdb34bb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -56,7 +56,7 @@
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -1336,7 +1336,7 @@
private CancellationSignal mFaceCancelSignal;
private FingerprintManager mFpm;
private FaceManager mFaceManager;
- private List<FaceSensorProperties> mFaceSensorProperties;
+ private List<FaceSensorPropertiesInternal> mFaceSensorProperties;
private boolean mFingerprintLockedOut;
private TelephonyManager mTelephonyManager;
@@ -1778,7 +1778,7 @@
}
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
mFaceManager = (FaceManager) context.getSystemService(Context.FACE_SERVICE);
- mFaceSensorProperties = mFaceManager.getSensorProperties();
+ mFaceSensorProperties = mFaceManager.getSensorPropertiesInternal();
}
if (mFpm != null || mFaceManager != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index f4c865e..4657b06 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -75,8 +75,10 @@
Key.HAS_SEEN_BUBBLES_EDUCATION,
Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION,
Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
- Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
+ Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
+ Key.HAS_SEEN_PRIORITY_ONBOARDING
})
+ // TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
public @interface Key {
@Deprecated
String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 1ebe648..c4a305e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -86,6 +86,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -121,6 +122,7 @@
private final TunerService mTunerService;
private DisplayManager.DisplayListener mDisplayListener;
private CameraAvailabilityListener mCameraListener;
+ private final UserTracker mUserTracker;
//TODO: These are piecemeal being updated to Points for now to support non-square rounded
// corners. for now it is only supposed when reading the intrinsic size from the drawables with
@@ -198,11 +200,13 @@
public ScreenDecorations(Context context,
@Main Handler handler,
BroadcastDispatcher broadcastDispatcher,
- TunerService tunerService) {
+ TunerService tunerService,
+ UserTracker userTracker) {
super(context);
mMainHandler = handler;
mBroadcastDispatcher = broadcastDispatcher;
mTunerService = tunerService;
+ mUserTracker = userTracker;
}
@Override
@@ -306,7 +310,8 @@
// Watch color inversion and invert the overlay as needed.
if (mColorInversionSetting == null) {
mColorInversionSetting = new SecureSetting(mContext, mHandler,
- Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+ mUserTracker.getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
updateColorInversion(value);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 911bf9e..a705ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -37,6 +37,7 @@
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import javax.inject.Inject;
@@ -66,7 +67,8 @@
@Inject
public WindowMagnification(Context context, @Main Handler mainHandler,
- CommandQueue commandQueue, ModeSwitchesController modeSwitchesController) {
+ CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
+ NavigationModeController navigationModeController) {
super(context);
mHandler = mainHandler;
mLastConfiguration = new Configuration(context.getResources().getConfiguration());
@@ -77,6 +79,9 @@
final WindowMagnificationController controller = new WindowMagnificationController(mContext,
mHandler, new SfVsyncFrameCallbackProvider(), null,
new SurfaceControl.Transaction(), this);
+ final int navBarMode = navigationModeController.addListener(
+ controller::onNavigationModeChanged);
+ controller.onNavigationModeChanged(navBarMode);
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
mContext, controller);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 3832ff30..c3474bb 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -17,6 +17,8 @@
package com.android.systemui.accessibility;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -117,6 +119,9 @@
// The boundary of magnification frame.
private final Rect mMagnificationFrameBoundary = new Rect();
+ private int mNavBarMode;
+ private int mNavGestureHeight;
+
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
private Locale mLocale;
@@ -195,6 +200,19 @@
R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin);
+ updateNavigationBarDimensions();
+ }
+
+ private void updateNavigationBarDimensions() {
+ if (!supportsSwipeUpGesture()) {
+ mNavGestureHeight = 0;
+ return;
+ }
+ mNavGestureHeight = (mDisplaySize.x > mDisplaySize.y)
+ ? mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_landscape)
+ : mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_gesture_height);
}
/**
@@ -239,6 +257,13 @@
}
}
+ /** Handles MirrorWindow position when the navigation bar mode changed. */
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ updateNavigationBarDimensions();
+ updateMirrorViewLayout();
+ }
+
/** Handles MirrorWindow position when the device rotation changed. */
private void onRotate() {
final Display display = mContext.getDisplay();
@@ -246,6 +271,7 @@
display.getRealSize(mDisplaySize);
setMagnificationFrameBoundary();
mRotation = display.getRotation();
+ updateNavigationBarDimensions();
if (!isWindowVisible()) {
return;
@@ -401,15 +427,23 @@
* moved close to the screen edges.
*/
private void updateMirrorViewLayout() {
+ if (!isWindowVisible()) {
+ return;
+ }
+ final int maxMirrorViewX = mDisplaySize.x - mMirrorView.getWidth();
+ final int maxMirrorViewY = mDisplaySize.y - mMirrorView.getHeight() - mNavGestureHeight;
WindowManager.LayoutParams params =
(WindowManager.LayoutParams) mMirrorView.getLayoutParams();
params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
+ // If nav bar mode supports swipe-up gesture, the Y position of mirror view should not
+ // overlap nav bar window to prevent window-dragging obscured.
+ if (supportsSwipeUpGesture()) {
+ params.y = Math.min(params.y, maxMirrorViewY);
+ }
// Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
// able to move close to the screen edges.
- final int maxMirrorViewX = mDisplaySize.x - mMirrorView.getWidth();
- final int maxMirrorViewY = mDisplaySize.y - mMirrorView.getHeight();
final float translationX;
final float translationY;
if (params.x < 0) {
@@ -621,6 +655,10 @@
return mMirrorView != null;
}
+ private boolean supportsSwipeUpGesture() {
+ return mNavBarMode == NAV_BAR_MODE_2BUTTON || mNavBarMode == NAV_BAR_MODE_GESTURAL;
+ }
+
private CharSequence formatStateDescription(float scale) {
// Cache the locale-appropriate NumberFormat. Configuration locale is guaranteed
// non-null, so the first time this is called we will always get the appropriate
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 38a191c..b1ae56a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -36,7 +36,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -306,9 +306,9 @@
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
- final List<FingerprintSensorProperties> fingerprintSensorProperties =
- mFingerprintManager.getSensorProperties();
- for (FingerprintSensorProperties props : fingerprintSensorProperties) {
+ final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
+ mFingerprintManager.getSensorPropertiesInternal();
+ for (FingerprintSensorPropertiesInternal props : fingerprintSensorProperties) {
if (props.isAnyUdfpsType()) {
mUdfpsController = mUdfpsControllerFactory.get();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 289ffbe..c409d87 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -26,7 +26,7 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -53,7 +53,6 @@
import java.io.FileWriter;
import java.io.IOException;
-import java.util.List;
import javax.inject.Inject;
@@ -182,7 +181,8 @@
mLayoutParams = createLayoutParams(context);
int udfpsSensorId = -1;
- for (FingerprintSensorProperties props : mFingerprintManager.getSensorProperties()) {
+ for (FingerprintSensorPropertiesInternal props :
+ mFingerprintManager.getSensorPropertiesInternal()) {
if (props.isAnyUdfpsType()) {
udfpsSensorId = props.sensorId;
break;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index dff405c..90b64ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -88,7 +88,6 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -112,8 +111,9 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index f2fba23..0dcd1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -16,6 +16,13 @@
package com.android.systemui.bubbles;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -78,10 +85,10 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
-import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.RelativeTouchListener;
-import com.android.systemui.util.animation.PhysicsAnimator;
-import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -92,12 +99,6 @@
import java.util.List;
import java.util.function.Consumer;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-
/**
* Renders bubbles in a stack and handles animating expanded and collapsed states.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
index 71faf4a..b3c552d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
@@ -10,8 +10,8 @@
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
import com.android.systemui.R
-import com.android.systemui.util.DismissCircleView
-import com.android.systemui.util.animation.PhysicsAnimator
+import com.android.wm.shell.common.DismissCircleView
+import com.android.wm.shell.animation.PhysicsAnimator
/*
* View that handles interactions between DismissCircleView and BubbleStackView.
@@ -29,7 +29,7 @@
var isShowing = false
private val animator = PhysicsAnimator.getInstance(circle)
- private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY);
+ private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
private val DISMISS_SCRIM_FADE_MS = 200
init {
setLayoutParams(LayoutParams(
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index f2a4f15..9f88ee5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -32,8 +32,8 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.util.animation.PhysicsAnimator;
-import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 46ef9bc..b7490a5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -36,9 +36,9 @@
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleStackView;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.animation.PhysicsAnimator;
-import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 08902f8..d2eaf0d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -40,8 +40,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import dagger.Module;
import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 658f46e..2f0fd99 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -16,7 +16,6 @@
package com.android.systemui.controls.controller
-import android.app.ActivityManager
import android.content.ComponentName
import android.content.Context
import android.os.IBinder
@@ -30,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
import java.util.concurrent.atomic.AtomicBoolean
@@ -40,7 +40,8 @@
open class ControlsBindingControllerImpl @Inject constructor(
private val context: Context,
@Background private val backgroundExecutor: DelayableExecutor,
- private val lazyController: Lazy<ControlsController>
+ private val lazyController: Lazy<ControlsController>,
+ userTracker: UserTracker
) : ControlsBindingController {
companion object {
@@ -56,7 +57,7 @@
}
}
- private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
+ private var currentUser = userTracker.userHandle
override val currentUserId: Int
get() = currentUser.identifier
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 495872f..d3d24be 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -16,7 +16,6 @@
package com.android.systemui.controls.controller
-import android.app.ActivityManager
import android.app.PendingIntent
import android.app.backup.BackupManager
import android.content.BroadcastReceiver
@@ -46,6 +45,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.globalactions.GlobalActionsDialog
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -56,14 +56,15 @@
@SysUISingleton
class ControlsControllerImpl @Inject constructor (
- private val context: Context,
- @Background private val executor: DelayableExecutor,
- private val uiController: ControlsUiController,
- private val bindingController: ControlsBindingController,
- private val listingController: ControlsListingController,
- private val broadcastDispatcher: BroadcastDispatcher,
- optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
- dumpManager: DumpManager
+ private val context: Context,
+ @Background private val executor: DelayableExecutor,
+ private val uiController: ControlsUiController,
+ private val bindingController: ControlsBindingController,
+ private val listingController: ControlsListingController,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
+ dumpManager: DumpManager,
+ userTracker: UserTracker
) : Dumpable, ControlsController {
companion object {
@@ -85,7 +86,7 @@
private var seedingInProgress = false
private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
- private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
+ private var currentUser = userTracker.userHandle
override val currentUserId
get() = currentUser.identifier
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 0d4439f..2d76ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -16,7 +16,6 @@
package com.android.systemui.controls.management
-import android.app.ActivityManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.ServiceInfo
@@ -29,6 +28,7 @@
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
@@ -56,14 +56,16 @@
class ControlsListingControllerImpl @VisibleForTesting constructor(
private val context: Context,
@Background private val backgroundExecutor: Executor,
- private val serviceListingBuilder: (Context) -> ServiceListing
+ private val serviceListingBuilder: (Context) -> ServiceListing,
+ userTracker: UserTracker
) : ControlsListingController {
@Inject
- constructor(context: Context, executor: Executor): this(
+ constructor(context: Context, executor: Executor, userTracker: UserTracker): this(
context,
executor,
- ::createServiceListing
+ ::createServiceListing,
+ userTracker
)
private var serviceListing = serviceListingBuilder(context)
@@ -78,7 +80,7 @@
private var availableServices = emptyList<ServiceInfo>()
private var userChangeInProgress = AtomicInteger(0)
- override var currentUserId = ActivityManager.getCurrentUser()
+ override var currentUserId = userTracker.userId
private set
private val serviceListingCallback = ServiceListing.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 9d8e73a..e50fd6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -134,7 +134,7 @@
// Cameras that support "self illumination," via IR for example, don't need low light
// environment mitigation.
- boolean needsLowLightMitigation = faceManager.getSensorProperties().stream()
+ boolean needsLowLightMitigation = faceManager.getSensorPropertiesInternal().stream()
.anyMatch((properties) -> !properties.supportsSelfIllumination);
if (!needsLowLightMitigation) {
return Optional.empty();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 4863999..d80aafb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -32,7 +32,7 @@
import com.android.systemui.R
import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS
import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.util.animation.PhysicsAnimator
+import com.android.wm.shell.animation.PhysicsAnimator
import com.android.systemui.util.concurrency.DelayableExecutor
private const val FLING_SLOP = 1000000
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 5d63cc7..6f6ee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -636,13 +636,13 @@
Assert.isMainThread()
val removed = mediaEntries.remove(key)
if (useMediaResumption && removed?.resumeAction != null &&
- !isBlockedFromResume(removed?.packageName)) {
+ !isBlockedFromResume(removed.packageName)) {
Log.d(TAG, "Not removing $key because resumable")
// Move to resume key (aka package name) if that key doesn't already exist.
val resumeAction = getResumeMediaAction(removed.resumeAction!!)
val updated = removed.copy(token = null, actions = listOf(resumeAction),
actionsToShowInCompact = listOf(0), active = false, resumption = true)
- val pkg = removed?.packageName
+ val pkg = removed.packageName
val migrate = mediaEntries.put(pkg, updated) == null
// Notify listeners of "new" controls when migrating or removed and update when not
if (migrate) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt b/packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt
index b887225..00273bc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt
@@ -8,7 +8,7 @@
import android.view.ViewGroup
import android.widget.HorizontalScrollView
import com.android.systemui.Gefingerpoken
-import com.android.systemui.util.animation.physicsAnimator
+import com.android.wm.shell.animation.physicsAnimator
/**
* A ScrollView used in Media that doesn't limit itself to the childs bounds. This is useful
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java
deleted file mode 100644
index 8e8b7f3..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip.tv.dagger;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.pip.tv.PipControlsView;
-import com.android.systemui.pip.tv.PipControlsViewController;
-import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Scope;
-
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-
-/**
- * Component for injecting into Pip related classes.
- */
-@Subcomponent
-public interface TvPipComponent {
- /**
- * Builder for {@link StatusBarComponent}.
- */
- @Subcomponent.Builder
- interface Builder {
- @BindsInstance
- TvPipComponent.Builder pipControlsView(PipControlsView pipControlsView);
- TvPipComponent build();
- }
-
- /**
- * Scope annotation for singleton items within the PipComponent.
- */
- @Documented
- @Retention(RUNTIME)
- @Scope
- @interface PipScope {}
-
- /**
- * Creates a StatusBarWindowViewController.
- */
- @TvPipComponent.PipScope
- PipControlsViewController getPipControlsViewController();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 0fbd73b..f56e6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -16,25 +16,23 @@
package com.android.systemui.privacy
-import android.app.ActivityManager
import android.app.AppOpsManager
-import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.UserInfo
import android.os.UserHandle
-import android.os.UserManager
import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.systemui.Dumpable
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
-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.dump.DumpManager
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
@@ -48,9 +46,8 @@
private val appOpsController: AppOpsController,
@Main uiExecutor: DelayableExecutor,
@Background private val bgExecutor: Executor,
- private val broadcastDispatcher: BroadcastDispatcher,
private val deviceConfigProxy: DeviceConfigProxy,
- private val userManager: UserManager,
+ private val userTracker: UserTracker,
dumpManager: DumpManager
) : Dumpable {
@@ -153,13 +150,16 @@
}
@VisibleForTesting
- internal var userSwitcherReceiver = Receiver()
- set(value) {
- unregisterReceiver()
- field = value
- if (listening) registerReceiver()
+ internal var userTrackerCallback = object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ update(true)
}
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ update(true)
+ }
+ }
+
init {
deviceConfigProxy.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_PRIVACY,
@@ -168,20 +168,18 @@
dumpManager.registerDumpable(TAG, this)
}
- private fun unregisterReceiver() {
- broadcastDispatcher.unregisterReceiver(userSwitcherReceiver)
+ private fun unregisterListener() {
+ userTracker.removeCallback(userTrackerCallback)
}
private fun registerReceiver() {
- broadcastDispatcher.registerReceiver(userSwitcherReceiver, intentFilter,
- null /* handler */, UserHandle.ALL)
+ userTracker.addCallback(userTrackerCallback, bgExecutor)
}
private fun update(updateUsers: Boolean) {
bgExecutor.execute {
if (updateUsers) {
- val currentUser = ActivityManager.getCurrentUser()
- currentUserIds = userManager.getProfiles(currentUser).map { it.id }
+ currentUserIds = userTracker.userProfiles.map { it.id }
}
updateListAndNotifyChanges.run()
}
@@ -206,7 +204,7 @@
update(true)
} else {
appOpsController.removeCallback(OPS, cb)
- unregisterReceiver()
+ unregisterListener()
// Make sure that we remove all indicators and notify listeners if we are not
// listening anymore due to indicators being disabled
update(false)
@@ -275,14 +273,6 @@
fun onFlagMicCameraChanged(flag: Boolean) {}
}
- internal inner class Receiver : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- if (intentFilter.hasAction(intent.action)) {
- update(true)
- }
- }
- }
-
private class NotifyChangesToCallback(
private val callback: Callback?,
private val list: List<PrivacyItem>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index eba4465..ac55fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -31,7 +31,7 @@
import com.android.systemui.R;
import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.util.animation.PhysicsAnimator;
+import com.android.wm.shell.animation.PhysicsAnimator;
/**
* Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
index fa33284..1e239b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
@@ -17,30 +17,44 @@
package com.android.systemui.qs;
import com.android.systemui.R;
+import com.android.systemui.util.ViewController;
import javax.inject.Inject;
-public class QSContainerImplController {
- private final QSContainerImpl mView;
+class QSContainerImplController extends ViewController<QSContainerImpl> {
private final QuickStatusBarHeaderController mQuickStatusBarHeaderController;
private QSContainerImplController(QSContainerImpl view,
QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
- mView = view;
+ super(view);
mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder
.setQuickStatusBarHeader(mView.findViewById(R.id.header)).build();
}
+ @Override
+ public void init() {
+ super.init();
+ mQuickStatusBarHeaderController.init();
+ }
+
public void setListening(boolean listening) {
mQuickStatusBarHeaderController.setListening(listening);
}
- public static class Builder {
+ @Override
+ protected void onViewAttached() {
+ }
+
+ @Override
+ protected void onViewDetached() {
+ }
+
+ static class Builder {
private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder;
private QSContainerImpl mView;
@Inject
- public Builder(
+ Builder(
QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 6e4ab9a..84563a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -20,6 +20,8 @@
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -34,6 +36,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
@@ -57,6 +60,7 @@
import com.android.systemui.R.dimen;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -75,6 +79,7 @@
private final ActivityStarter mActivityStarter;
private final UserInfoController mUserInfoController;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final UserTracker mUserTracker;
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
private PageIndicator mPageIndicator;
@@ -115,11 +120,12 @@
@Inject
public QSFooterImpl(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
ActivityStarter activityStarter, UserInfoController userInfoController,
- DeviceProvisionedController deviceProvisionedController) {
+ DeviceProvisionedController deviceProvisionedController, UserTracker userTracker) {
super(context, attrs);
mActivityStarter = activityStarter;
mUserInfoController = userInfoController;
mDeviceProvisionedController = deviceProvisionedController;
+ mUserTracker = userTracker;
}
@VisibleForTesting
@@ -127,7 +133,8 @@
this(context, attrs,
Dependency.get(ActivityStarter.class),
Dependency.get(UserInfoController.class),
- Dependency.get(DeviceProvisionedController.class));
+ Dependency.get(DeviceProvisionedController.class),
+ Dependency.get(UserTracker.class));
}
@Override
@@ -150,6 +157,19 @@
mActionsContainer = findViewById(R.id.qs_footer_actions_container);
mEditContainer = findViewById(R.id.qs_footer_actions_edit_container);
mBuildText = findViewById(R.id.build);
+ mBuildText.setOnLongClickListener(view -> {
+ CharSequence buildText = mBuildText.getText();
+ if (!TextUtils.isEmpty(buildText)) {
+ ClipboardManager service =
+ mUserTracker.getUserContext().getSystemService(ClipboardManager.class);
+ String label = mContext.getString(R.string.build_number_clip_data_label);
+ service.setPrimaryClip(ClipData.newPlainText(label, buildText));
+ Toast.makeText(mContext, R.string.build_number_copy_toast, Toast.LENGTH_SHORT)
+ .show();
+ return true;
+ }
+ return false;
+ });
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
@@ -176,6 +196,7 @@
mBuildText.setSelected(true);
mShouldShowBuildText = true;
} else {
+ mBuildText.setText(null);
mShouldShowBuildText = false;
mBuildText.setSelected(false);
}
@@ -317,12 +338,14 @@
mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
+ mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
}
private void updateVisibilities() {
mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
- TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
+ TunerService.isTunerEnabled(mContext, mUserTracker.getUserHandle()) ? View.VISIBLE
+ : View.INVISIBLE);
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.INVISIBLE);
mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
@@ -376,15 +399,16 @@
: MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
if (mSettingsButton.isTunerClick()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- if (TunerService.isTunerEnabled(mContext)) {
- TunerService.showResetRequest(mContext, () -> {
- // Relaunch settings so that the tuner disappears.
- startSettingsActivity();
- });
+ if (TunerService.isTunerEnabled(mContext, mUserTracker.getUserHandle())) {
+ TunerService.showResetRequest(mContext, mUserTracker.getUserHandle(),
+ () -> {
+ // Relaunch settings so that the tuner disappears.
+ startSettingsActivity();
+ });
} else {
Toast.makeText(getContext(), R.string.tuner_toast,
Toast.LENGTH_LONG).show();
- TunerService.setTunerEnabled(mContext, true);
+ TunerService.setTunerEnabled(mContext, mUserTracker.getUserHandle(), true);
}
startSettingsActivity();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index f1bb899..3a78365 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -142,7 +142,7 @@
mQSContainerImplController = mQSContainerImplControllerBuilder
.setQSContainerImpl((QSContainerImpl) view)
.build();
-
+ mQSContainerImplController.init();
mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
@@ -367,14 +367,13 @@
if (DEBUG) Log.d(TAG, "setListening " + listening);
mListening = listening;
mQSContainerImplController.setListening(listening);
- mHeader.setListening(listening);
mFooter.setListening(listening);
mQSPanel.setListening(mListening, mQsExpanded);
}
@Override
public void setHeaderListening(boolean listening) {
- mHeader.setListening(listening);
+ mQSContainerImplController.setListening(listening);
mFooter.setListening(listening);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 290ab85..000fd1c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -30,6 +30,7 @@
void openPanels();
Context getContext();
Context getUserContext();
+ int getUserId();
UiEventLogger getUiEventLogger();
Collection<QSTile> getTiles();
void addCallback(Callback callback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ae925d1..fdc0a60e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -25,7 +25,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.PointF;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.Handler;
@@ -57,6 +56,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSliderView;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
@@ -114,6 +114,7 @@
private final QSLogger mQSLogger;
protected final UiEventLogger mUiEventLogger;
protected QSTileHost mHost;
+ private final UserTracker mUserTracker;
@Nullable
protected QSSecurityFooter mSecurityFooter;
@@ -157,7 +158,8 @@
BroadcastDispatcher broadcastDispatcher,
QSLogger qsLogger,
MediaHost mediaHost,
- UiEventLogger uiEventLogger
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker
) {
super(context, attrs);
mUsingMediaPlayer = useQsMediaPlayer(context);
@@ -173,6 +175,7 @@
mDumpManager = dumpManager;
mBroadcastDispatcher = broadcastDispatcher;
mUiEventLogger = uiEventLogger;
+ mUserTracker = userTracker;
setOrientation(VERTICAL);
@@ -221,7 +224,7 @@
}
protected void addSecurityFooter() {
- mSecurityFooter = new QSSecurityFooter(this, mContext);
+ mSecurityFooter = new QSSecurityFooter(this, mContext, mUserTracker);
}
protected void addViewsAboveTiles() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index afc5be4e..0891972 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.qs;
-import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyEventLogger;
import android.content.Context;
@@ -45,6 +44,7 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
@@ -61,8 +61,7 @@
private final SecurityController mSecurityController;
private final ActivityStarter mActivityStarter;
private final Handler mMainHandler;
-
- private final UserManager mUm;
+ private final UserTracker mUserTracker;
private AlertDialog mDialog;
private QSTileHost mHost;
@@ -73,7 +72,7 @@
private int mFooterTextId;
private int mFooterIconId;
- public QSSecurityFooter(QSPanel qsPanel, Context context) {
+ public QSSecurityFooter(QSPanel qsPanel, Context context, UserTracker userTracker) {
mRootView = LayoutInflater.from(context)
.inflate(R.layout.quick_settings_footer, qsPanel, false);
mRootView.setOnClickListener(this);
@@ -85,7 +84,7 @@
mActivityStarter = Dependency.get(ActivityStarter.class);
mSecurityController = Dependency.get(SecurityController.class);
mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
- mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mUserTracker = userTracker;
}
public void setHostEnvironment(QSTileHost host) {
@@ -138,7 +137,7 @@
private void handleRefreshState() {
final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
- final UserInfo currentUser = mUm.getUserInfo(ActivityManager.getCurrentUser());
+ final UserInfo currentUser = mUserTracker.getUserInfo();
final boolean isDemoDevice = UserManager.isDeviceInDemoMode(mContext) && currentUser != null
&& currentUser.isDemo();
final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 9a63a56..0d0d012 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -14,7 +14,6 @@
package com.android.systemui.qs;
-import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -49,6 +48,7 @@
import com.android.systemui.qs.external.TileLifecycleManager;
import com.android.systemui.qs.external.TileServices;
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.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -99,6 +99,7 @@
private int mCurrentUser;
private final Optional<StatusBar> mStatusBarOptional;
private Context mUserContext;
+ private UserTracker mUserTracker;
@Inject
public QSTileHost(Context context,
@@ -113,7 +114,8 @@
BroadcastDispatcher broadcastDispatcher,
Optional<StatusBar> statusBarOptional,
QSLogger qsLogger,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
mIconController = iconController;
mContext = context;
mUserContext = context;
@@ -125,12 +127,13 @@
mBroadcastDispatcher = broadcastDispatcher;
mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
- mServices = new TileServices(this, bgLooper, mBroadcastDispatcher);
+ mServices = new TileServices(this, bgLooper, mBroadcastDispatcher, userTracker);
mStatusBarOptional = statusBarOptional;
mQsFactories.add(defaultFactory);
pluginManager.addPluginListener(this, QSFactory.class, true);
mDumpManager.registerDumpable(TAG, this);
+ mUserTracker = userTracker;
mainHandler.post(() -> {
// This is technically a hack to avoid circular dependency of
@@ -230,6 +233,11 @@
}
@Override
+ public int getUserId() {
+ return mCurrentUser;
+ }
+
+ @Override
public TileServices getTileServices() {
return mServices;
}
@@ -248,9 +256,9 @@
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
- int currentUser = ActivityManager.getCurrentUser();
+ int currentUser = mUserTracker.getUserId();
if (currentUser != mCurrentUser) {
- mUserContext = mContext.createContextAsUser(UserHandle.of(currentUser), 0);
+ mUserContext = mUserTracker.getUserContext();
if (mAutoTiles != null) {
mAutoTiles.changeUser(UserHandle.of(currentUser));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index affb7b9..ea036f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -38,6 +38,7 @@
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -70,9 +71,11 @@
BroadcastDispatcher broadcastDispatcher,
QSLogger qsLogger,
MediaHost mediaHost,
- UiEventLogger uiEventLogger
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker
) {
- super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger);
+ super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger,
+ userTracker);
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
applyBottomMargin((View) mRegularTileLayout);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8fec5a2..a9fbc74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -17,28 +17,16 @@
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.annotation.ColorInt;
-import android.app.ActivityManager;
-import android.app.AlarmManager;
+import android.app.AlarmManager.AlarmClockInfo;
import android.content.Context;
-import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.AlarmClock;
-import android.provider.Settings;
-import android.service.notification.ZenModeConfig;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
import android.view.ContextThemeWrapper;
@@ -54,92 +42,48 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.DualToneHandler;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.privacy.PrivacyChipEvent;
-import com.android.systemui.privacy.PrivacyItem;
-import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.qs.QSDetail.Callback;
-import com.android.systemui.qs.carrier.QSCarrierGroup;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
-import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.DateView;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.RingerModeTracker;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Locale;
import java.util.Objects;
-import javax.inject.Inject;
-import javax.inject.Named;
-
/**
* View that contains the top-most bits of the screen (primarily the status bar with date, time, and
* battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
* contents.
*/
-public class QuickStatusBarHeader extends RelativeLayout implements
- View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
- ZenModeController.Callback, LifecycleOwner {
- private static final String TAG = "QuickStatusBarHeader";
- private static final boolean DEBUG = false;
+public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwner {
- /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
- private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
- private static final int FADE_ANIMATION_DURATION_MS = 300;
- private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
- private final NextAlarmController mAlarmController;
- private final ZenModeController mZenController;
- private final StatusBarIconController mStatusBarIconController;
- private final ActivityStarter mActivityStarter;
-
- private QSPanel mQsPanel;
-
private boolean mExpanded;
- private boolean mListening;
private boolean mQsDisabled;
- private QSCarrierGroup mCarrierGroup;
protected QuickQSPanel mHeaderQsPanel;
- protected QSTileHost mHost;
- private TintedIconManager mIconManager;
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
private TouchAnimator mPrivacyChipAlphaAnimator;
private DualToneHandler mDualToneHandler;
- private final CommandQueue mCommandQueue;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
private View mHeaderTextContainerView;
- private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
- private AlarmManager.AlarmClockInfo mNextAlarm;
-
private ImageView mNextAlarmIcon;
/** {@link TextView} containing the actual text indicating when the next alarm will go off. */
private TextView mNextAlarmTextView;
@@ -149,22 +93,13 @@
private TextView mRingerModeTextView;
private View mRingerContainer;
private Clock mClockView;
- private DateView mDateView;
private OngoingPrivacyChip mPrivacyChip;
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
- private RingerModeTracker mRingerModeTracker;
- private DemoModeController mDemoModeController;
- private DemoMode mDemoModeReceiver;
- private boolean mAllIndicatorsEnabled;
- private boolean mMicCameraIndicatorsEnabled;
- private PrivacyItemController mPrivacyItemController;
- private final UiEventLogger mUiEventLogger;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
- private boolean mHasTopCutout = false;
private int mStatusBarPaddingTop = 0;
private int mRoundedCornerPadding = 0;
private int mContentMarginStart;
@@ -174,57 +109,11 @@
private int mCutOutPaddingRight;
private float mExpandedHeaderAlpha = 1.0f;
private float mKeyguardExpansionFraction;
- private boolean mPrivacyChipLogged = false;
- private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
- @Override
- public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) {
- mPrivacyChip.setPrivacyList(privacyItems);
- setChipVisibility(!privacyItems.isEmpty());
- }
-
- @Override
- public void onFlagAllChanged(boolean flag) {
- if (mAllIndicatorsEnabled != flag) {
- mAllIndicatorsEnabled = flag;
- update();
- }
- }
-
- @Override
- public void onFlagMicCameraChanged(boolean flag) {
- if (mMicCameraIndicatorsEnabled != flag) {
- mMicCameraIndicatorsEnabled = flag;
- update();
- }
- }
-
- private void update() {
- StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
- setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
- }
- };
-
- @Inject
- public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- NextAlarmController nextAlarmController, ZenModeController zenModeController,
- StatusBarIconController statusBarIconController,
- ActivityStarter activityStarter, PrivacyItemController privacyItemController,
- CommandQueue commandQueue, RingerModeTracker ringerModeTracker,
- UiEventLogger uiEventLogger, DemoModeController demoModeController) {
+ public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
- mAlarmController = nextAlarmController;
- mZenController = zenModeController;
- mStatusBarIconController = statusBarIconController;
- mActivityStarter = activityStarter;
- mPrivacyItemController = privacyItemController;
mDualToneHandler = new DualToneHandler(
new ContextThemeWrapper(context, R.style.QSHeaderTheme));
- mCommandQueue = commandQueue;
- mRingerModeTracker = ringerModeTracker;
- mUiEventLogger = uiEventLogger;
- mDemoModeController = demoModeController;
}
@Override
@@ -234,11 +123,6 @@
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
- StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
- // Ignore privacy icons because they show in the space above QQS
- iconContainer.addIgnoredSlots(getIgnoredIconSlots());
- iconContainer.setShouldRestrictIcons(false);
- mIconManager = new TintedIconManager(iconContainer, mCommandQueue);
// Views corresponding to the header info section (e.g. ringer and next alarm).
mHeaderTextContainerView = findViewById(R.id.header_text_container);
@@ -246,36 +130,18 @@
mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
mNextAlarmTextView = findViewById(R.id.next_alarm_text);
mNextAlarmContainer = findViewById(R.id.alarm_container);
- mNextAlarmContainer.setOnClickListener(this::onClick);
mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
mRingerModeTextView = findViewById(R.id.ringer_mode_text);
mRingerContainer = findViewById(R.id.ringer_container);
- mRingerContainer.setOnClickListener(this::onClick);
mPrivacyChip = findViewById(R.id.privacy_chip);
- mPrivacyChip.setOnClickListener(this::onClick);
- mCarrierGroup = findViewById(R.id.carrier_group);
-
updateResources();
Rect tintArea = new Rect(0, 0, 0, 0);
- int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorForeground);
- float intensity = getColorIntensity(colorForeground);
- int fillColor = mDualToneHandler.getSingleColor(intensity);
-
// Set light text on the header icons because they will always be on a black background
applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
- // Set the correct tint for the status icons so they contrast
- mIconManager.setTint(fillColor);
- mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
- mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
-
mClockView = findViewById(R.id.clock);
- mClockView.setOnClickListener(this);
- mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
- mDateView = findViewById(R.id.date);
mSpace = findViewById(R.id.space);
// Tint for the battery icons are handled in setupHost()
@@ -287,33 +153,28 @@
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
mRingerModeTextView.setSelected(true);
mNextAlarmTextView.setSelected(true);
+ }
- mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
- mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+ void onAttach(TintedIconManager iconManager) {
+ int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.colorForeground);
+ float intensity = getColorIntensity(colorForeground);
+ int fillColor = mDualToneHandler.getSingleColor(intensity);
+
+ // Set the correct tint for the status icons so they contrast
+ iconManager.setTint(fillColor);
+ mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
+ mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
}
public QuickQSPanel getHeaderQsPanel() {
return mHeaderQsPanel;
}
- private List<String> getIgnoredIconSlots() {
- ArrayList<String> ignored = new ArrayList<>();
- if (getChipEnabled()) {
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_camera));
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_microphone));
- if (mAllIndicatorsEnabled) {
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_location));
- }
- }
-
- return ignored;
- }
-
- private void updateStatusText() {
- boolean changed = updateRingerStatus() || updateAlarmStatus();
+ void updateStatusText(int ringerMode, AlarmClockInfo nextAlarm, boolean zenOverridingRinger,
+ boolean use24HourFormat) {
+ boolean changed = updateRingerStatus(ringerMode, zenOverridingRinger)
+ || updateAlarmStatus(nextAlarm, use24HourFormat);
if (changed) {
boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
@@ -323,32 +184,17 @@
}
}
- private void setChipVisibility(boolean chipVisible) {
- if (chipVisible && getChipEnabled()) {
- mPrivacyChip.setVisibility(View.VISIBLE);
- // Makes sure that the chip is logged as viewed at most once each time QS is opened
- // mListening makes sure that the callback didn't return after the user closed QS
- if (!mPrivacyChipLogged && mListening) {
- mPrivacyChipLogged = true;
- mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW);
- }
- } else {
- mPrivacyChip.setVisibility(View.GONE);
- }
- }
-
- private boolean updateRingerStatus() {
+ private boolean updateRingerStatus(int ringerMode, boolean zenOverridingRinger) {
boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
CharSequence originalRingerText = mRingerModeTextView.getText();
boolean ringerVisible = false;
- if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
- mZenController.getConsolidatedPolicy())) {
- if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ if (!zenOverridingRinger) {
+ if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
ringerVisible = true;
- } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
+ } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
mRingerModeTextView.setText(R.string.qs_status_phone_muted);
ringerVisible = true;
@@ -362,14 +208,14 @@
!Objects.equals(originalRingerText, mRingerModeTextView.getText());
}
- private boolean updateAlarmStatus() {
+ private boolean updateAlarmStatus(AlarmClockInfo nextAlarm, boolean use24HourFormat) {
boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
CharSequence originalAlarmText = mNextAlarmTextView.getText();
boolean alarmVisible = false;
- if (mNextAlarm != null) {
+ if (nextAlarm != null) {
alarmVisible = true;
- mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
+ mNextAlarmTextView.setText(formatNextAlarm(nextAlarm, use24HourFormat));
}
mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
@@ -416,7 +262,7 @@
setMinimumHeight(sbHeight + qqsHeight);
}
- private void updateResources() {
+ void updateResources() {
Resources resources = mContext.getResources();
updateMinimumHeight();
@@ -526,18 +372,6 @@
}
@Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> {
- mRingerMode = ringer;
- updateStatusText();
- });
- mStatusBarIconController.addIconGroup(mIconManager);
- mDemoModeController.addCallback(mDemoModeReceiver);
- requestApplyInsets();
- }
-
- @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
// Handle padding of the clock
DisplayCutout cutout = insets.getDisplayCutout();
@@ -560,17 +394,14 @@
if (cutout != null) {
Rect topCutout = cutout.getBoundingRectTop();
if (topCutout.isEmpty() || cornerCutout) {
- mHasTopCutout = false;
lp.width = 0;
mSpace.setVisibility(View.GONE);
} else {
- mHasTopCutout = true;
lp.width = topCutout.width();
mSpace.setVisibility(View.VISIBLE);
}
}
mSpace.setLayoutParams(lp);
- setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
mCutOutPaddingLeft = padding.first;
mCutOutPaddingRight = padding.second;
mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
@@ -608,103 +439,14 @@
0);
}
- @Override
- @VisibleForTesting
- public void onDetachedFromWindow() {
- setListening(false);
- mRingerModeTracker.getRingerModeInternal().removeObservers(this);
- mStatusBarIconController.removeIconGroup(mIconManager);
- mDemoModeController.removeCallback(mDemoModeReceiver);
- super.onDetachedFromWindow();
- }
-
- public void setListening(boolean listening) {
- if (listening == mListening) {
- return;
- }
- mHeaderQsPanel.setListening(listening);
- if (mHeaderQsPanel.switchTileLayout()) {
- updateResources();
- }
- mListening = listening;
-
- if (listening) {
- mZenController.addCallback(this);
- mAlarmController.addCallback(this);
- mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
- // Get the most up to date info
- mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
- mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
- mPrivacyItemController.addCallback(mPICCallback);
- } else {
- mZenController.removeCallback(this);
- mAlarmController.removeCallback(this);
- mLifecycle.setCurrentState(Lifecycle.State.CREATED);
- mPrivacyItemController.removeCallback(mPICCallback);
- mPrivacyChipLogged = false;
- }
- }
-
- @Override
- public void onClick(View v) {
- if (v == mClockView) {
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- AlarmClock.ACTION_SHOW_ALARMS), 0);
- } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
- if (mNextAlarm.getShowIntent() != null) {
- mActivityStarter.postStartActivityDismissingKeyguard(
- mNextAlarm.getShowIntent());
- } else {
- Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- AlarmClock.ACTION_SHOW_ALARMS), 0);
- }
- } else if (v == mPrivacyChip) {
- // If the privacy chip is visible, it means there were some indicators
- Handler mUiHandler = new Handler(Looper.getMainLooper());
- mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK);
- mUiHandler.post(() -> {
- mActivityStarter.postStartActivityDismissingKeyguard(
- new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
- mHost.collapsePanels();
- });
- } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- Settings.ACTION_SOUND_SETTINGS), 0);
- }
- }
-
- @Override
- public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarm = nextAlarm;
- updateStatusText();
- }
-
- @Override
- public void onZenChanged(int zen) {
- updateStatusText();
- }
-
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- updateStatusText();
- }
-
public void updateEverything() {
post(() -> setClickable(!mExpanded));
}
public void setQSPanel(final QSPanel qsPanel) {
- mQsPanel = qsPanel;
- setupHost(qsPanel.getHost());
- }
-
- public void setupHost(final QSTileHost host) {
- mHost = host;
//host.setHeaderView(mExpandIndicator);
- mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
- mHeaderQsPanel.setHost(host, null /* No customization in header */);
-
+ mHeaderQsPanel.setQSPanelAndHeader(qsPanel, this);
+ mHeaderQsPanel.setHost(qsPanel.getHost(), null /* No customization in header */);
Rect tintArea = new Rect(0, 0, 0, 0);
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
@@ -718,12 +460,11 @@
mHeaderQsPanel.setCallback(qsPanelCallback);
}
- private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
+ private String formatNextAlarm(AlarmClockInfo info, boolean use24HourFormat) {
if (info == null) {
return "";
}
- String skeleton = android.text.format.DateFormat
- .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
+ String skeleton = use24HourFormat ? "EHm" : "Ehma";
String pattern = android.text.format.DateFormat
.getBestDateTimePattern(Locale.getDefault(), skeleton);
return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
@@ -774,37 +515,4 @@
updateHeaderTextContainerAlphaAnimator();
}
}
-
- private boolean getChipEnabled() {
- return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
- }
-
- private static class ClockDemoModeReceiver implements DemoMode {
- private Clock mClockView;
-
- @Override
- public List<String> demoCommands() {
- return List.of(COMMAND_CLOCK);
- }
-
- ClockDemoModeReceiver(Clock clockView) {
- mClockView = clockView;
- }
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- mClockView.dispatchDemoCommand(command, args);
- }
-
- @Override
- public void onDemoModeStarted() {
- mClockView.onDemoModeStarted();
- }
-
- @Override
- public void onDemoModeFinished() {
- mClockView.onDemoModeFinished();
- }
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index d899acb..676a300 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -16,36 +16,393 @@
package com.android.systemui.qs;
+import android.app.AlarmManager.AlarmClockInfo;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.AlarmClock;
+import android.provider.Settings;
+import android.service.notification.ZenModeConfig;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.privacy.OngoingPrivacyChip;
+import com.android.systemui.privacy.PrivacyChipEvent;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.CommandQueue;
+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.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
-public class QuickStatusBarHeaderController {
- private final QuickStatusBarHeader mView;
+/**
+ * Controller for {@link QuickStatusBarHeader}.
+ */
+class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader> {
+ private static final String TAG = "QuickStatusBarHeader";
+
+ private final ZenModeController mZenModeController;
+ private final NextAlarmController mNextAlarmController;
+ private final PrivacyItemController mPrivacyItemController;
+ private final RingerModeTracker mRingerModeTracker;
+ private final ActivityStarter mActivityStarter;
+ private final UiEventLogger mUiEventLogger;
private final QSCarrierGroupController mQSCarrierGroupController;
+ private final QuickQSPanel mHeaderQsPanel;
+ private final LifecycleRegistry mLifecycle;
+ private final OngoingPrivacyChip mPrivacyChip;
+ private final Clock mClockView;
+ private final View mNextAlarmContainer;
+ private final View mRingerContainer;
+ private final QSTileHost mQSTileHost;
+ private final StatusBarIconController mStatusBarIconController;
+ private final CommandQueue mCommandQueue;
+ private final DemoModeController mDemoModeController;
+ private final UserTracker mUserTracker;
+ private final StatusIconContainer mIconContainer;
+ private final StatusBarIconController.TintedIconManager mIconManager;
+ private final DemoMode mDemoModeReceiver;
+
+ private boolean mListening;
+ private AlarmClockInfo mNextAlarm;
+ private boolean mAllIndicatorsEnabled;
+ private boolean mMicCameraIndicatorsEnabled;
+ private boolean mPrivacyChipLogged;
+ private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
+
+ private final ZenModeController.Callback mZenModeControllerCallback = new Callback() {
+ @Override
+ public void onZenChanged(int zen) {
+ mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+ use24HourFormat());
+ }
+
+ @Override
+ public void onConfigChanged(ZenModeConfig config) {
+ mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+ use24HourFormat());
+ }
+ };
+
+ private boolean use24HourFormat() {
+ return android.text.format.DateFormat.is24HourFormat(
+ mView.getContext(), mUserTracker.getUserId());
+
+ }
+
+ private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() {
+ @Override
+ public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
+ mNextAlarm = nextAlarm;
+ mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+ use24HourFormat());
+ }
+ };
+
+ private final LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
+ }
+ };
+
+ private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
+ @Override
+ public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
+ mPrivacyChip.setPrivacyList(privacyItems);
+ setChipVisibility(!privacyItems.isEmpty());
+ }
+
+ @Override
+ public void onFlagAllChanged(boolean flag) {
+ if (mAllIndicatorsEnabled != flag) {
+ mAllIndicatorsEnabled = flag;
+ update();
+ }
+ }
+
+ @Override
+ public void onFlagMicCameraChanged(boolean flag) {
+ if (mMicCameraIndicatorsEnabled != flag) {
+ mMicCameraIndicatorsEnabled = flag;
+ update();
+ }
+ }
+
+ private void update() {
+ StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons);
+ iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+ }
+ };
+
+ private View.OnClickListener mOnClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (v == mClockView) {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ AlarmClock.ACTION_SHOW_ALARMS), 0);
+ } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
+ if (mNextAlarm.getShowIntent() != null) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ mNextAlarm.getShowIntent());
+ } else {
+ Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ AlarmClock.ACTION_SHOW_ALARMS), 0);
+ }
+ } else if (v == mPrivacyChip) {
+ // If the privacy chip is visible, it means there were some indicators
+ Handler mUiHandler = new Handler(Looper.getMainLooper());
+ mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK);
+ mUiHandler.post(() -> {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
+ mQSTileHost.collapsePanels();
+ });
+ } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ Settings.ACTION_SOUND_SETTINGS), 0);
+ }
+ }
+ };
private QuickStatusBarHeaderController(QuickStatusBarHeader view,
+ ZenModeController zenModeController, NextAlarmController nextAlarmController,
+ PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker,
+ ActivityStarter activityStarter, UiEventLogger uiEventLogger,
+ QSTileHost qsTileHost, StatusBarIconController statusBarIconController,
+ CommandQueue commandQueue, DemoModeController demoModeController,
+ UserTracker userTracker,
QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
- mView = view;
+ super(view);
+ mZenModeController = zenModeController;
+ mNextAlarmController = nextAlarmController;
+ mPrivacyItemController = privacyItemController;
+ mRingerModeTracker = ringerModeTracker;
+ mActivityStarter = activityStarter;
+ mUiEventLogger = uiEventLogger;
+ mQSTileHost = qsTileHost;
+ mStatusBarIconController = statusBarIconController;
+ mCommandQueue = commandQueue;
+ mDemoModeController = demoModeController;
+ mUserTracker = userTracker;
+ mLifecycle = new LifecycleRegistry(mLifecycleOwner);
+
mQSCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
.build();
+
+
+ mPrivacyChip = mView.findViewById(R.id.privacy_chip);
+ mHeaderQsPanel = mView.findViewById(R.id.quick_qs_panel);
+ mNextAlarmContainer = mView.findViewById(R.id.alarm_container);
+ mClockView = mView.findViewById(R.id.clock);
+ mRingerContainer = mView.findViewById(R.id.ringer_container);
+ mIconContainer = mView.findViewById(R.id.statusIcons);
+
+ mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mCommandQueue);
+ mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mRingerModeTracker.getRingerModeInternal().observe(mLifecycleOwner, ringer -> {
+ mRingerMode = ringer;
+ mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+ use24HourFormat());
+ });
+
+ mClockView.setOnClickListener(mOnClickListener);
+ mNextAlarmContainer.setOnClickListener(mOnClickListener);
+ mRingerContainer.setOnClickListener(mOnClickListener);
+ mPrivacyChip.setOnClickListener(mOnClickListener);
+
+ // Ignore privacy icons because they show in the space above QQS
+ mIconContainer.addIgnoredSlots(getIgnoredIconSlots());
+ mIconContainer.setShouldRestrictIcons(false);
+ mStatusBarIconController.addIconGroup(mIconManager);
+
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+
+ setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
+
+ mView.onAttach(mIconManager);
+
+ mDemoModeController.addCallback(mDemoModeReceiver);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mRingerModeTracker.getRingerModeInternal().removeObservers(mLifecycleOwner);
+ mClockView.setOnClickListener(null);
+ mNextAlarmContainer.setOnClickListener(null);
+ mRingerContainer.setOnClickListener(null);
+ mPrivacyChip.setOnClickListener(null);
+ mStatusBarIconController.removeIconGroup(mIconManager);
+ mDemoModeController.removeCallback(mDemoModeReceiver);
+ setListening(false);
}
public void setListening(boolean listening) {
mQSCarrierGroupController.setListening(listening);
- // TODO: move mView.setListening logic into here.
- mView.setListening(listening);
+
+ if (listening == mListening) {
+ return;
+ }
+ mListening = listening;
+
+ mHeaderQsPanel.setListening(listening);
+ if (mHeaderQsPanel.switchTileLayout()) {
+ mView.updateResources();
+ }
+
+ if (listening) {
+ mZenModeController.addCallback(mZenModeControllerCallback);
+ mNextAlarmController.addCallback(mNextAlarmChangeCallback);
+ mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
+ // Get the most up to date info
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+ mPrivacyItemController.addCallback(mPICCallback);
+ } else {
+ mZenModeController.removeCallback(mZenModeControllerCallback);
+ mNextAlarmController.removeCallback(mNextAlarmChangeCallback);
+ mLifecycle.setCurrentState(Lifecycle.State.CREATED);
+ mPrivacyItemController.removeCallback(mPICCallback);
+ mPrivacyChipLogged = false;
+ }
+ }
+
+ private void setChipVisibility(boolean chipVisible) {
+ if (chipVisible && getChipEnabled()) {
+ mPrivacyChip.setVisibility(View.VISIBLE);
+ // Makes sure that the chip is logged as viewed at most once each time QS is opened
+ // mListening makes sure that the callback didn't return after the user closed QS
+ if (!mPrivacyChipLogged && mListening) {
+ mPrivacyChipLogged = true;
+ mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW);
+ }
+ } else {
+ mPrivacyChip.setVisibility(View.GONE);
+ }
+ }
+
+ private List<String> getIgnoredIconSlots() {
+ ArrayList<String> ignored = new ArrayList<>();
+ if (getChipEnabled()) {
+ 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));
+ if (mAllIndicatorsEnabled) {
+ ignored.add(mView.getResources().getString(
+ com.android.internal.R.string.status_bar_location));
+ }
+ }
+
+ return ignored;
+ }
+
+ private boolean getChipEnabled() {
+ return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
+ }
+
+ private boolean isZenOverridingRinger() {
+ return ZenModeConfig.isZenOverridingRinger(mZenModeController.getZen(),
+ mZenModeController.getConsolidatedPolicy());
}
- public static class Builder {
+ private static class ClockDemoModeReceiver implements DemoMode {
+ private Clock mClockView;
+
+ @Override
+ public List<String> demoCommands() {
+ return List.of(COMMAND_CLOCK);
+ }
+
+ ClockDemoModeReceiver(Clock clockView) {
+ mClockView = clockView;
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ mClockView.dispatchDemoCommand(command, args);
+ }
+
+ @Override
+ public void onDemoModeStarted() {
+ mClockView.onDemoModeStarted();
+ }
+
+ @Override
+ public void onDemoModeFinished() {
+ mClockView.onDemoModeFinished();
+ }
+ }
+
+ static class Builder {
+ private final ZenModeController mZenModeController;
+ private final NextAlarmController mNextAlarmController;
+ private final PrivacyItemController mPrivacyItemController;
+ private final RingerModeTracker mRingerModeTracker;
+ private final ActivityStarter mActivityStarter;
+ private final UiEventLogger mUiEventLogger;
+ private final QSTileHost mQsTileHost;
+ private final StatusBarIconController mStatusBarIconController;
+ private final CommandQueue mCommandQueue;
+ private final DemoModeController mDemoModeController;
+ private final UserTracker mUserTracker;
private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder;
private QuickStatusBarHeader mView;
@Inject
- public Builder(QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+ Builder(ZenModeController zenModeController, NextAlarmController nextAlarmController,
+ PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker,
+ ActivityStarter activityStarter, UiEventLogger uiEventLogger, QSTileHost qsTileHost,
+ StatusBarIconController statusBarIconController, CommandQueue commandQueue,
+ DemoModeController demoModeController, UserTracker userTracker,
+ QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+ mZenModeController = zenModeController;
+ mNextAlarmController = nextAlarmController;
+ mPrivacyItemController = privacyItemController;
+ mRingerModeTracker = ringerModeTracker;
+ mActivityStarter = activityStarter;
+ mUiEventLogger = uiEventLogger;
+ mQsTileHost = qsTileHost;
+ mStatusBarIconController = statusBarIconController;
+ mCommandQueue = commandQueue;
+ mDemoModeController = demoModeController;
+ mUserTracker = userTracker;
mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder;
}
@@ -54,8 +411,13 @@
return this;
}
- public QuickStatusBarHeaderController build() {
- return new QuickStatusBarHeaderController(mView, mQSCarrierGroupControllerBuilder);
+
+ QuickStatusBarHeaderController build() {
+ return new QuickStatusBarHeaderController(mView, mZenModeController,
+ mNextAlarmController, mPrivacyItemController, mRingerModeTracker,
+ mActivityStarter, mUiEventLogger, mQsTileHost, mStatusBarIconController,
+ mCommandQueue, mDemoModeController, mUserTracker,
+ mQSCarrierGroupControllerBuilder);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index 65d81505..3ee3e11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -16,7 +16,6 @@
package com.android.systemui.qs;
-import android.app.ActivityManager;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -37,10 +36,6 @@
protected abstract void handleValueChanged(int value, boolean observedChange);
- protected SecureSetting(Context context, Handler handler, String settingName) {
- this(context, handler, settingName, ActivityManager.getCurrentUser());
- }
-
public SecureSetting(Context context, Handler handler, String settingName, int userId) {
super(handler);
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index bffeb3e..e049025 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -607,6 +607,12 @@
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
+ // Do not draw background for the holder that's currently being dragged
+ if (holder == mCurrentDrag) {
+ continue;
+ }
+ // Do not draw background for holders before the edit index (header and current
+ // tiles)
if (holder.getAdapterPosition() == 0 ||
holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) {
continue;
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 73c6504..b795a5f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -17,7 +17,6 @@
package com.android.systemui.qs.customize;
import android.Manifest.permission;
-import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +39,7 @@
import com.android.systemui.qs.QSTileHost;
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.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -58,16 +58,18 @@
private final Executor mMainExecutor;
private final Executor mBgExecutor;
private final Context mContext;
+ private final UserTracker mUserTracker;
private TileStateListener mListener;
private boolean mFinished;
@Inject
- public TileQueryHelper(Context context,
+ public TileQueryHelper(Context context, UserTracker userTracker,
@Main Executor mainExecutor, @Background Executor bgExecutor) {
mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
+ mUserTracker = userTracker;
}
public void setListener(TileStateListener listener) {
@@ -207,7 +209,7 @@
Collection<QSTile> params = host.getTiles();
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServicesAsUser(
- new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
+ new Intent(TileService.ACTION_QS_TILE), 0, mUserTracker.getUserId());
String stockTiles = mContext.getString(R.string.quick_settings_tiles_stock);
for (ResolveInfo info : services) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 19c7b6c..6e28cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -18,7 +18,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -304,8 +303,7 @@
}
private Intent resolveIntent(Intent i) {
- ResolveInfo result = mContext.getPackageManager().resolveActivityAsUser(i, 0,
- ActivityManager.getCurrentUser());
+ ResolveInfo result = mContext.getPackageManager().resolveActivityAsUser(i, 0, mUser);
return result != null ? new Intent(TileService.ACTION_QS_TILE_PREFERENCES)
.setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index cfa8fb6..7e76e57 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.qs.external;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -26,7 +25,6 @@
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
-import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
@@ -36,6 +34,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
+import com.android.systemui.settings.UserTracker;
import java.util.List;
import java.util.Objects;
@@ -60,6 +59,7 @@
private final TileServices mServices;
private final TileLifecycleManager mStateManager;
private final Handler mHandler;
+ private final UserTracker mUserTracker;
private boolean mBindRequested;
private boolean mBindAllowed;
private boolean mBound;
@@ -73,25 +73,26 @@
private boolean mStarted = false;
TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
- Tile tile, BroadcastDispatcher broadcastDispatcher) {
- this(tileServices, handler, new TileLifecycleManager(handler,
+ Tile tile, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker) {
+ this(tileServices, handler, userTracker, new TileLifecycleManager(handler,
tileServices.getContext(), tileServices, tile, new Intent().setComponent(component),
- new UserHandle(ActivityManager.getCurrentUser()), broadcastDispatcher));
+ userTracker.getUserHandle(), broadcastDispatcher));
}
@VisibleForTesting
- TileServiceManager(TileServices tileServices, Handler handler,
+ TileServiceManager(TileServices tileServices, Handler handler, UserTracker userTracker,
TileLifecycleManager tileLifecycleManager) {
mServices = tileServices;
mHandler = handler;
mStateManager = tileLifecycleManager;
+ mUserTracker = userTracker;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
Context context = mServices.getContext();
- context.registerReceiverAsUser(mUninstallReceiver,
- new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler);
+ context.registerReceiverAsUser(mUninstallReceiver, userTracker.getUserHandle(), filter,
+ null, mHandler);
}
boolean isLifecycleStarted() {
@@ -279,7 +280,7 @@
queryIntent.setPackage(pkgName);
PackageManager pm = context.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServicesAsUser(
- queryIntent, 0, ActivityManager.getCurrentUser());
+ queryIntent, 0, mUserTracker.getUserId());
for (ResolveInfo info : services) {
if (Objects.equals(info.serviceInfo.packageName, component.getPackageName())
&& Objects.equals(info.serviceInfo.name, component.getClassName())) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 2863d08..35cf2a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -39,6 +39,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -62,15 +63,18 @@
private final Handler mMainHandler;
private final QSTileHost mHost;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final UserTracker mUserTracker;
private int mMaxBound = DEFAULT_MAX_BOUND;
- public TileServices(QSTileHost host, Looper looper, BroadcastDispatcher broadcastDispatcher) {
+ public TileServices(QSTileHost host, Looper looper, BroadcastDispatcher broadcastDispatcher,
+ UserTracker userTracker) {
mHost = host;
mContext = mHost.getContext();
mBroadcastDispatcher = broadcastDispatcher;
mHandler = new Handler(looper);
mMainHandler = new Handler(Looper.getMainLooper());
+ mUserTracker = userTracker;
mBroadcastDispatcher.registerReceiver(
mRequestListeningReceiver,
new IntentFilter(TileService.ACTION_REQUEST_LISTENING),
@@ -104,7 +108,7 @@
protected TileServiceManager onCreateTileService(ComponentName component, Tile tile,
BroadcastDispatcher broadcastDispatcher) {
return new TileServiceManager(this, mHandler, component, tile,
- broadcastDispatcher);
+ broadcastDispatcher, mUserTracker);
}
public void freeService(CustomTile tile, TileServiceManager service) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index dfd7e2c..5a81676 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -31,7 +31,6 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -521,9 +520,9 @@
protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
- userRestriction, ActivityManager.getCurrentUser());
+ userRestriction, mHost.getUserId());
if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
- userRestriction, ActivityManager.getCurrentUser())) {
+ userRestriction, mHost.getUserId())) {
state.disabledByPolicy = true;
mEnforcedAdmin = admin;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 347ef45..98782f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -38,6 +38,7 @@
import com.android.systemui.qs.SecureSetting;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
import javax.inject.Inject;
@@ -61,13 +62,14 @@
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
- QSLogger qsLogger
+ QSLogger qsLogger,
+ UserTracker userTracker
) {
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
activityStarter, qsLogger);
mSetting = new SecureSetting(mContext, mainHandler,
- Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
// mHandler is the background handler so calling this is OK
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ec8b143..2076cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,7 +19,6 @@
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
-import android.app.ActivityManager;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -203,7 +202,7 @@
break;
default:
Uri conditionId = ZenModeConfig.toTimeCondition(mContext, zenDuration,
- ActivityManager.getCurrentUser(), true).id;
+ mHost.getUserId(), true).id;
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
conditionId, TAG);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index f11683d..0ae1170 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -75,9 +75,6 @@
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipAnimationController;
-import com.android.systemui.pip.phone.PipUtils;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -94,6 +91,9 @@
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEvents;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.phone.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -108,6 +108,7 @@
import dagger.Lazy;
+
/**
* Class to send information from overview to launcher with a binder.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index df03c3e..0aa9d4d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -48,6 +48,7 @@
private long mTotalBytes;
private MediaMuxer mMuxer;
private boolean mMic;
+ private boolean mStarted;
private int mTrackId = -1;
@@ -263,10 +264,14 @@
* start recording
* @throws IllegalStateException if recording fails to initialize
*/
- public void start() throws IllegalStateException {
- if (mThread != null) {
- Log.e(TAG, "a recording is being done in parallel or stop is not called");
+ public synchronized void start() throws IllegalStateException {
+ if (mStarted) {
+ if (mThread == null) {
+ throw new IllegalStateException("Recording stopped and can't restart (single use)");
+ }
+ throw new IllegalStateException("Recording already started");
}
+ mStarted = true;
mAudioRecord.startRecording();
if (mMic) mAudioRecordMic.startRecording();
Log.d(TAG, "channel count " + mAudioRecord.getChannelCount());
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 26d408f..c7a8fa2 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -40,6 +40,11 @@
val userHandle: UserHandle
/**
+ * [UserInfo] for current user
+ */
+ val userInfo: UserInfo
+
+ /**
* List of profiles associated with the current user.
*/
val userProfiles: List<UserInfo>
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 4cc0eee..049685f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -82,6 +82,12 @@
override val userContentResolver: ContentResolver
get() = userContext.contentResolver
+ override val userInfo: UserInfo
+ get() {
+ val user = userId
+ return userProfiles.first { it.id == user }
+ }
+
/**
* Returns a [List<UserInfo>] of all profiles associated with the current user.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 37ae791..0184fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -58,12 +58,14 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.systemui.tracing.ProtoTracer;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
/**
* This class takes the functions from IStatusBar that come in on
@@ -159,6 +161,7 @@
*/
private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;
private ProtoTracer mProtoTracer;
+ private final @Nullable CommandRegistry mRegistry;
/**
* These methods are called back on the main thread.
@@ -368,11 +371,12 @@
}
public CommandQueue(Context context) {
- this(context, null);
+ this(context, null, null);
}
- public CommandQueue(Context context, ProtoTracer protoTracer) {
+ public CommandQueue(Context context, ProtoTracer protoTracer, CommandRegistry registry) {
mProtoTracer = protoTracer;
+ mRegistry = registry;
context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
// We always have default display.
setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE);
@@ -1013,6 +1017,34 @@
}
}
+ @Override
+ public void passThroughShellCommand(String[] args, ParcelFileDescriptor pfd) {
+ final FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
+ final PrintWriter pw = new PrintWriter(fos);
+ // This is mimicking Binder#dumpAsync, but on this side of the binder. Might be possible
+ // to just throw this work onto the handler just like the other messages
+ Thread thr = new Thread("Sysui.passThroughShellCommand") {
+ public void run() {
+ try {
+ if (mRegistry == null) {
+ return;
+ }
+
+ // Registry blocks this thread until finished
+ mRegistry.onShellCommand(pw, args);
+ } finally {
+ pw.flush();
+ try {
+ // Close the file descriptor so the TransferPipe finishes its thread
+ pfd.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ };
+ thr.start();
+ }
+
private final class H extends Handler {
private H(Looper l) {
super(l);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 8bf134d..bb76ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -40,6 +40,9 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;
@@ -52,13 +55,18 @@
import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -77,6 +85,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import dagger.Lazy;
@@ -106,6 +115,9 @@
private final NotificationEntryManager mEntryManager;
private final MediaDataManager mMediaDataManager;
+ private final NotifPipeline mNotifPipeline;
+ private final NotifCollection mNotifCollection;
+ private final boolean mUsingNotifPipeline;
@Nullable
private Lazy<NotificationShadeWindowController> mNotificationShadeWindowController;
@@ -189,6 +201,9 @@
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
+ NotifPipeline notifPipeline,
+ NotifCollection notifCollection,
+ FeatureFlags featureFlags,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfig,
MediaDataManager mediaDataManager) {
@@ -206,17 +221,87 @@
mEntryManager = notificationEntryManager;
mMainExecutor = mainExecutor;
mMediaDataManager = mediaDataManager;
+ mNotifPipeline = notifPipeline;
+ mNotifCollection = notifCollection;
- notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+ if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ setupNEM();
+ mUsingNotifPipeline = false;
+ } else {
+ setupNotifPipeline();
+ mUsingNotifPipeline = true;
+ }
+
+ mShowCompactMediaSeekbar = "true".equals(
+ DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
+
+ deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ mContext.getMainExecutor(),
+ mPropertiesChangedListener);
+ }
+
+ private void setupNotifPipeline() {
+ mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
+ @Override
+ public void onEntryAdded(@NonNull NotificationEntry entry) {
+ mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationEntry entry) {
+ mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
+ }
+
+ @Override
+ public void onEntryBind(NotificationEntry entry, StatusBarNotification sbn) {
+ findAndUpdateMediaNotifications();
+ }
+
+ @Override
+ public void onEntryRemoved(@NonNull NotificationEntry entry, int reason) {
+ removeEntry(entry);
+ }
+
+ @Override
+ public void onEntryCleanUp(@NonNull NotificationEntry entry) {
+ removeEntry(entry);
+ }
+ });
+
+ mMediaDataManager.addListener(new MediaDataManager.Listener() {
+ @Override
+ public void onMediaDataLoaded(@NonNull String key,
+ @Nullable String oldKey, @NonNull MediaData data) {
+ }
+
+ @Override
+ public void onMediaDataRemoved(@NonNull String key) {
+ mNotifPipeline.getAllNotifs()
+ .stream()
+ .filter(entry -> Objects.equals(entry.getKey(), key))
+ .findAny()
+ .ifPresent(entry -> {
+ // TODO(b/160713608): "removing" this notification won't happen and
+ // won't send the 'deleteIntent' if the notification is ongoing.
+ mNotifCollection.dismissNotification(entry,
+ getDismissedByUserStats(entry));
+ });
+ }
+ });
+ }
+
+ private void setupNEM() {
+ mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
- mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
+ mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
- mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
+ mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
@@ -231,8 +316,8 @@
@Override
public void onEntryRemoved(
- NotificationEntry entry,
- NotificationVisibility visibility,
+ @NonNull NotificationEntry entry,
+ @Nullable NotificationVisibility visibility,
boolean removedByUser,
int reason) {
removeEntry(entry);
@@ -242,20 +327,49 @@
// Pending entries are never inflated, and will never generate a call to onEntryRemoved().
// This can happen when notifications are added and canceled before inflation. Add this
// separate listener for cleanup, since media inflation occurs onPendingEntryAdded().
- notificationEntryManager.addCollectionListener(new NotifCollectionListener() {
+ mEntryManager.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryCleanUp(@NonNull NotificationEntry entry) {
removeEntry(entry);
}
});
- mShowCompactMediaSeekbar = "true".equals(
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
+ mMediaDataManager.addListener(new MediaDataManager.Listener() {
+ @Override
+ public void onMediaDataLoaded(@NonNull String key,
+ @Nullable String oldKey, @NonNull MediaData data) {
+ }
- deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- mContext.getMainExecutor(),
- mPropertiesChangedListener);
+ @Override
+ public void onMediaDataRemoved(@NonNull String key) {
+ NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ // TODO(b/160713608): "removing" this notification won't happen and
+ // won't send the 'deleteIntent' if the notification is ongoing.
+ mEntryManager.performRemoveNotification(entry.getSbn(),
+ getDismissedByUserStats(entry),
+ NotificationListenerService.REASON_CANCEL);
+ }
+ }
+ });
+ }
+
+ private DismissedByUserStats getDismissedByUserStats(NotificationEntry entry) {
+ final int activeNotificationsCount;
+ if (mUsingNotifPipeline) {
+ activeNotificationsCount = mNotifPipeline.getShadeListCount();
+ } else {
+ activeNotificationsCount = mEntryManager.getActiveNotificationsCount();
+ }
+ return new DismissedByUserStats(
+ NotificationStats.DISMISSAL_SHADE, // Add DISMISSAL_MEDIA?
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ activeNotificationsCount,
+ /* visible= */ true,
+ NotificationLogger.getNotificationLocation(entry)));
}
private void removeEntry(NotificationEntry entry) {
@@ -299,14 +413,24 @@
if (mMediaNotificationKey == null) {
return null;
}
- synchronized (mEntryManager) {
- NotificationEntry entry = mEntryManager
+ if (mUsingNotifPipeline) {
+ // TODO(b/169655596): Either add O(1) lookup, or cache this icon?
+ return mNotifPipeline.getAllNotifs().stream()
+ .filter(entry -> Objects.equals(entry.getKey(), mMediaNotificationKey))
+ .findAny()
+ .map(entry -> entry.getIcons().getShelfIcon())
+ .map(StatusBarIconView::getSourceIcon)
+ .orElse(null);
+ } else {
+ synchronized (mEntryManager) {
+ NotificationEntry entry = mEntryManager
.getActiveNotificationUnfiltered(mMediaNotificationKey);
- if (entry == null || entry.getIcons().getShelfIcon() == null) {
- return null;
- }
+ if (entry == null || entry.getIcons().getShelfIcon() == null) {
+ return null;
+ }
- return entry.getIcons().getShelfIcon().getSourceIcon();
+ return entry.getIcons().getShelfIcon().getSourceIcon();
+ }
}
}
@@ -321,94 +445,110 @@
}
public void findAndUpdateMediaNotifications() {
+ boolean metaDataChanged;
+ if (mUsingNotifPipeline) {
+ // TODO(b/169655907): get the semi-filtered notifications for current user
+ Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
+ metaDataChanged = findPlayingMediaNotification(allNotifications);
+ } else {
+ synchronized (mEntryManager) {
+ Collection<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
+ metaDataChanged = findPlayingMediaNotification(allNotifications);
+ }
+
+ if (metaDataChanged) {
+ mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
+ }
+
+ }
+ dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
+ }
+
+ /**
+ * Find a notification and media controller associated with the playing media session, and
+ * update this manager's internal state.
+ * @return whether the current MediaMetadata changed (and needs to be announced to listeners).
+ */
+ private boolean findPlayingMediaNotification(
+ @NonNull Collection<NotificationEntry> allNotifications) {
boolean metaDataChanged = false;
+ // Promote the media notification with a controller in 'playing' state, if any.
+ NotificationEntry mediaNotification = null;
+ MediaController controller = null;
+ for (NotificationEntry entry : allNotifications) {
+ if (entry.isMediaNotification()) {
+ final MediaSession.Token token =
+ entry.getSbn().getNotification().extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION);
+ if (token != null) {
+ MediaController aController = new MediaController(mContext, token);
+ if (PlaybackState.STATE_PLAYING
+ == getMediaControllerPlaybackState(aController)) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
+ + entry.getSbn().getKey());
+ }
+ mediaNotification = entry;
+ controller = aController;
+ break;
+ }
+ }
+ }
+ }
+ if (mediaNotification == null) {
+ // Still nothing? OK, let's just look for live media sessions and see if they match
+ // one of our notifications. This will catch apps that aren't (yet!) using media
+ // notifications.
- synchronized (mEntryManager) {
- Collection<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
+ if (mMediaSessionManager != null) {
+ // TODO: Should this really be for all users? It appears that inactive users
+ // can't have active sessions, which would mean it is fine.
+ final List<MediaController> sessions =
+ mMediaSessionManager.getActiveSessionsForUser(null, UserHandle.USER_ALL);
- // Promote the media notification with a controller in 'playing' state, if any.
- NotificationEntry mediaNotification = null;
- MediaController controller = null;
- for (NotificationEntry entry : allNotifications) {
- if (entry.isMediaNotification()) {
- final MediaSession.Token token =
- entry.getSbn().getNotification().extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION);
- if (token != null) {
- MediaController aController = new MediaController(mContext, token);
- if (PlaybackState.STATE_PLAYING ==
- getMediaControllerPlaybackState(aController)) {
+ for (MediaController aController : sessions) {
+ // now to see if we have one like this
+ final String pkg = aController.getPackageName();
+
+ for (NotificationEntry entry : allNotifications) {
+ if (entry.getSbn().getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
+ Log.v(TAG, "DEBUG_MEDIA: found controller matching "
+ entry.getSbn().getKey());
}
- mediaNotification = entry;
controller = aController;
+ mediaNotification = entry;
break;
}
}
}
}
- if (mediaNotification == null) {
- // Still nothing? OK, let's just look for live media sessions and see if they match
- // one of our notifications. This will catch apps that aren't (yet!) using media
- // notifications.
+ }
- if (mMediaSessionManager != null) {
- // TODO: Should this really be for all users?
- final List<MediaController> sessions
- = mMediaSessionManager.getActiveSessionsForUser(
- null,
- UserHandle.USER_ALL);
-
- for (MediaController aController : sessions) {
- // now to see if we have one like this
- final String pkg = aController.getPackageName();
-
- for (NotificationEntry entry : allNotifications) {
- if (entry.getSbn().getPackageName().equals(pkg)) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: found controller matching "
- + entry.getSbn().getKey());
- }
- controller = aController;
- mediaNotification = entry;
- break;
- }
- }
- }
- }
+ if (controller != null && !sameSessions(mMediaController, controller)) {
+ // We have a new media session
+ clearCurrentMediaNotificationSession();
+ mMediaController = controller;
+ mMediaController.registerCallback(mMediaListener);
+ mMediaMetadata = mMediaController.getMetadata();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
+ + mMediaController + ", receive metadata: " + mMediaMetadata);
}
- if (controller != null && !sameSessions(mMediaController, controller)) {
- // We have a new media session
- clearCurrentMediaNotificationSession();
- mMediaController = controller;
- mMediaController.registerCallback(mMediaListener);
- mMediaMetadata = mMediaController.getMetadata();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
- + mMediaController + ", receive metadata: " + mMediaMetadata);
- }
+ metaDataChanged = true;
+ }
- metaDataChanged = true;
- }
-
- if (mediaNotification != null
- && !mediaNotification.getSbn().getKey().equals(mMediaNotificationKey)) {
- mMediaNotificationKey = mediaNotification.getSbn().getKey();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
- + mMediaNotificationKey);
- }
+ if (mediaNotification != null
+ && !mediaNotification.getSbn().getKey().equals(mMediaNotificationKey)) {
+ mMediaNotificationKey = mediaNotification.getSbn().getKey();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ + mMediaNotificationKey);
}
}
- if (metaDataChanged) {
- mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
- }
-
- dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
+ return metaDataChanged;
}
public void clearCurrentMediaNotification() {
@@ -428,7 +568,7 @@
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.print(" mMediaSessionManager=");
pw.println(mMediaSessionManager);
pw.print(" mMediaNotificationKey=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
new file mode 100644
index 0000000..ce0a08c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.commandline
+
+import android.content.Context
+
+import com.android.systemui.Prefs
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+
+import java.io.PrintWriter
+import java.lang.IllegalStateException
+import java.util.concurrent.Executor
+import java.util.concurrent.FutureTask
+
+import javax.inject.Inject
+
+/**
+ * Registry / dispatcher for incoming shell commands. See [StatusBarManagerService] and
+ * [StatusBarShellCommand] for how things are set up. Commands come in here by way of the service
+ * like so:
+ *
+ * `adb shell cmd statusbar <command>`
+ *
+ * Where `cmd statusbar` send the shell command through to StatusBarManagerService, and
+ * <command> is either processed in system server, or sent through to IStatusBar (CommandQueue)
+ */
+@SysUISingleton
+class CommandRegistry @Inject constructor(
+ val context: Context,
+ @Main val mainExecutor: Executor
+) {
+ // To keep the command line parser hermetic, create a new one for every shell command
+ private val commandMap = mutableMapOf<String, CommandWrapper>()
+ private var initialized = false
+
+ /**
+ * Register a [Command] for a given name. The name here is the top-level namespace for
+ * the registered command. A command could look like this for instance:
+ *
+ * `adb shell cmd statusbar notifications list`
+ *
+ * Where `notifications` is the command that signifies which receiver to send the remaining args
+ * to.
+ *
+ * @param command String name of the command to register. Currently does not support aliases
+ * @param receiverFactory Creates an instance of the receiver on every command
+ * @param executor Pass an executor to offload your `receive` to another thread
+ */
+ @Synchronized
+ fun registerCommand(
+ name: String,
+ commandFactory: () -> Command,
+ executor: Executor
+ ) {
+ if (commandMap[name] != null) {
+ throw IllegalStateException("A command is already registered for ($name)")
+ }
+ commandMap[name] = CommandWrapper(commandFactory, executor)
+ }
+
+ /**
+ * Register a [Command] for a given name, to be executed on the main thread.
+ */
+ @Synchronized
+ fun registerCommand(name: String, commandFactory: () -> Command) {
+ registerCommand(name, commandFactory, mainExecutor)
+ }
+
+ /** Unregister a receiver */
+ @Synchronized
+ fun unregisterCommand(command: String) {
+ commandMap.remove(command)
+ }
+
+ private fun initializeCommands() {
+ initialized = true
+ // TODO: Might want a dedicated place for commands without a home. Currently
+ // this is here because Prefs.java is just an interface
+ registerCommand("prefs") { PrefsCommand(context) }
+ }
+
+ /**
+ * Receive a shell command and dispatch to the appropriate [Command]. Blocks until finished.
+ */
+ fun onShellCommand(pw: PrintWriter, args: Array<String>) {
+ if (!initialized) initializeCommands()
+
+ if (args.isEmpty()) {
+ help(pw)
+ return
+ }
+
+ val commandName = args[0]
+ val wrapper = commandMap[commandName]
+
+ if (wrapper == null) {
+ help(pw)
+ return
+ }
+
+ // Create a new instance of the command
+ val command = wrapper.commandFactory()
+
+ // Wrap the receive command in a task so that we can wait for its completion
+ val task = FutureTask<Unit> {
+ command.execute(pw, args.drop(1))
+ }
+
+ wrapper.executor.execute {
+ task.run()
+ }
+
+ // Wait for the future to complete
+ task.get()
+ }
+
+ private fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar <command>")
+ pw.println(" known commands:")
+ for (k in commandMap.keys) {
+ pw.println(" $k")
+ }
+ }
+}
+
+private const val TAG = "CommandRegistry"
+
+interface Command {
+ fun execute(pw: PrintWriter, args: List<String>)
+ fun help(pw: PrintWriter)
+}
+
+// Wrap commands in an executor package
+private data class CommandWrapper(val commandFactory: () -> Command, val executor: Executor)
+
+// Commands can go here for now, but they should move outside
+
+private class PrefsCommand(val context: Context) : Command {
+ override fun help(pw: PrintWriter) {
+ pw.println("usage: prefs <command> [args]")
+ pw.println("Available commands:")
+ pw.println(" list-prefs")
+ pw.println(" set-pref <pref name> <value>")
+ }
+
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ if (args.isEmpty()) {
+ help(pw)
+ return
+ }
+
+ val topLevel = args[0]
+
+ when (topLevel) {
+ "list-prefs" -> listPrefs(pw)
+ "set-pref" -> setPref(pw, args.drop(1))
+ else -> help(pw)
+ }
+ }
+
+ private fun listPrefs(pw: PrintWriter) {
+ pw.println("Available keys:")
+ for (field in Prefs.Key::class.java.declaredFields) {
+ pw.print(" ")
+ pw.println(field.get(Prefs.Key::class.java))
+ }
+ }
+
+ /**
+ * Sets a preference from [Prefs]
+ */
+ private fun setPref(pw: PrintWriter, args: List<String>) {
+ if (args.isEmpty()) {
+ pw.println("invalid arguments: $args")
+ return
+ }
+ val pref = args[0]
+
+ when (pref) {
+ Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING -> {
+ val value = Integer.parseInt(args[1])
+ Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, value != 0)
+ }
+ else -> {
+ pw.println("Cannot set pref ($pref)")
+ }
+ }
+ }
+}
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 969cd90..cee9c70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -28,6 +28,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
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;
@@ -39,10 +40,13 @@
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -110,6 +114,9 @@
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
+ NotifPipeline notifPipeline,
+ NotifCollection notifCollection,
+ FeatureFlags featureFlags,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfigProxy,
MediaDataManager mediaDataManager) {
@@ -120,6 +127,9 @@
notificationEntryManager,
mediaArtworkProcessor,
keyguardBypassController,
+ notifPipeline,
+ notifCollection,
+ featureFlags,
mainExecutor,
deviceConfigProxy,
mediaDataManager);
@@ -192,8 +202,11 @@
*/
@Provides
@SysUISingleton
- static CommandQueue provideCommandQueue(Context context, ProtoTracer protoTracer) {
- return new CommandQueue(context, protoTracer);
+ static CommandQueue provideCommandQueue(
+ Context context,
+ ProtoTracer protoTracer,
+ CommandRegistry registry) {
+ return new CommandQueue(context, protoTracer, registry);
}
/**
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 fdfd724..d617dff 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
@@ -291,6 +291,7 @@
mLogger.logDismissAll(userId);
try {
+ // TODO(b/169585328): Do not clear media player notifications
mStatusBarService.onClearAllNotifications(userId);
} catch (RemoteException e) {
// system process is dead if we're here.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 22ca496..7babbb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -172,14 +172,19 @@
private fun treeToMap(tree: NodeSpec): Map<NodeController, NodeSpec> {
val map = mutableMapOf<NodeController, NodeSpec>()
- registerNodes(tree, map)
+ try {
+ registerNodes(tree, map)
+ } catch (ex: DuplicateNodeException) {
+ logger.logDuplicateNodeInTree(tree, ex)
+ throw ex
+ }
return map
}
private fun registerNodes(node: NodeSpec, map: MutableMap<NodeController, NodeSpec>) {
if (map.containsKey(node.controller)) {
- throw RuntimeException("Node ${node.controller.nodeLabel} appears more than once")
+ throw DuplicateNodeException("Node ${node.controller.nodeLabel} appears more than once")
}
map[node.controller] = node
@@ -191,6 +196,8 @@
}
}
+private class DuplicateNodeException(message: String) : RuntimeException(message)
+
private class ShadeNode(
val controller: NodeController
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
index 19e156f..d274550 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
@@ -19,6 +19,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NotificationLog
+import java.lang.RuntimeException
import javax.inject.Inject
class ShadeViewDifferLogger @Inject constructor(
@@ -67,6 +68,15 @@
"Moving child view $str1 in $str2 to index $int1"
})
}
+
+ fun logDuplicateNodeInTree(node: NodeSpec, ex: RuntimeException) {
+ buffer.log(TAG, LogLevel.ERROR, {
+ str1 = ex.toString()
+ str2 = treeSpecToStr(node)
+ }, {
+ "$str1 when mapping tree: $str2"
+ })
+ }
}
private const val TAG = "NotifViewManager"
\ No newline at end of file
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 6820819..7698133 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
@@ -1303,7 +1303,8 @@
mView.clearNotifications(ROWS_GENTLE, closeShade);
}
- private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove, int selectedRows) {
+ private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove,
+ @SelectedRows int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
mNotifCollection.dismissAllNotifications(
@@ -1336,6 +1337,7 @@
}
if (selectedRows == ROWS_ALL) {
try {
+ // TODO(b/169585328): Do not clear media player notifications
mIStatusBarService.onClearAllNotifications(
mLockscreenUserManager.getCurrentUserId());
} catch (Exception ignored) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index efd6767..76c5baf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -169,7 +169,8 @@
String setting = split[0];
String spec = split[1];
// Populate all the settings. As they may not have been added in other users
- AutoAddSetting s = new AutoAddSetting(mContext, mHandler, setting, spec);
+ AutoAddSetting s = new AutoAddSetting(
+ mContext, mHandler, setting, mCurrentUser.getIdentifier(), spec);
mAutoAddSettingList.add(s);
} else {
Log.w(TAG, "Malformed item in array: " + tile);
@@ -319,8 +320,14 @@
private class AutoAddSetting extends SecureSetting {
private final String mSpec;
- AutoAddSetting(Context context, Handler handler, String setting, String tileSpec) {
- super(context, handler, setting);
+ AutoAddSetting(
+ Context context,
+ Handler handler,
+ String setting,
+ int userId,
+ String tileSpec
+ ) {
+ super(context, handler, setting, userId);
mSpec = tileSpec;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 0fdc80b..8e8a33f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -20,7 +20,6 @@
import static com.android.settingslib.Utils.updateLocationEnabled;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -43,6 +42,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.Utils;
import java.util.ArrayList;
@@ -60,6 +60,7 @@
private final Context mContext;
private final AppOpsController mAppOpsController;
private final BootCompleteCache mBootCompleteCache;
+ private final UserTracker mUserTracker;
private final H mHandler;
@@ -68,11 +69,13 @@
@Inject
public LocationControllerImpl(Context context, AppOpsController appOpsController,
@Main Looper mainLooper, @Background Handler backgroundHandler,
- BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache) {
+ BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache,
+ UserTracker userTracker) {
mContext = context;
mAppOpsController = appOpsController;
mBootCompleteCache = bootCompleteCache;
mHandler = new H(mainLooper);
+ mUserTracker = userTracker;
// Register to listen for changes in location settings.
IntentFilter filter = new IntentFilter();
@@ -113,7 +116,7 @@
public boolean setLocationEnabled(boolean enabled) {
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
- int currentUserId = ActivityManager.getCurrentUser();
+ int currentUserId = mUserTracker.getUserId();
if (isUserLocationRestricted(currentUserId)) {
return false;
}
@@ -134,7 +137,7 @@
LocationManager locationManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
return mBootCompleteCache.isBootComplete() && locationManager.isLocationEnabledForUser(
- UserHandle.of(ActivityManager.getCurrentUser()));
+ mUserTracker.getUserHandle());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index 7aeca64..c9d1b71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -284,25 +284,28 @@
mAnimator.setTarget(mIndicatorView);
mAnimator.setProperty(View.ALPHA);
mAnimator.addListener(new AnimatorListenerAdapter() {
+ boolean mCancelled;
+
@Override
public void onAnimationStart(Animator animation, boolean isReverse) {
- if (DEBUG) Log.d(TAG, "onAnimationStart");
+ if (DEBUG) Log.d(TAG, "AnimatorListenerAdapter#onAnimationStart");
+ mCancelled = false;
}
@Override
public void onAnimationCancel(Animator animation) {
- if (DEBUG) Log.d(TAG, "onAnimationCancel");
+ if (DEBUG) Log.d(TAG, "AnimatorListenerAdapter#onAnimationCancel");
+ mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
- if (DEBUG) Log.d(TAG, "onAnimationEnd");
-
- if (mState == STATE_APPEARING) {
- mState = STATE_SHOWN;
- } else if (mState == STATE_DISAPPEARING) {
- removeIndicatorView();
- mState = STATE_NOT_SHOWN;
+ if (DEBUG) Log.d(TAG, "AnimatorListenerAdapter#onAnimationEnd");
+ // When ValueAnimator#cancel() is called it always calls onAnimationCancel(...)
+ // and then onAnimationEnd(...). We, however, only want to proceed here if the
+ // animation ended "naturally".
+ if (!mCancelled) {
+ onAnimationFinished();
}
}
});
@@ -319,6 +322,17 @@
mAnimator.start();
}
+ private void onAnimationFinished() {
+ if (DEBUG) Log.d(TAG, "onAnimationFinished");
+
+ if (mState == STATE_APPEARING) {
+ mState = STATE_SHOWN;
+ } else if (mState == STATE_DISAPPEARING) {
+ removeIndicatorView();
+ mState = STATE_NOT_SHOWN;
+ }
+ }
+
private boolean hasActiveRecorders() {
for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) {
for (String activePackage : mAudioActivityObservers[index].getActivePackages()) {
@@ -330,6 +344,8 @@
}
private void removeIndicatorView() {
+ if (DEBUG) Log.d(TAG, "removeIndicatorView");
+
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
windowManager.removeView(mIndicatorView);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 0070dcf..4c724ae 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.tuner;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
@@ -22,6 +23,7 @@
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Build;
import android.os.Bundle;
+import android.os.UserHandle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
@@ -122,7 +124,8 @@
getActivity().finish();
return true;
case MENU_REMOVE:
- TunerService.showResetRequest(getContext(), new Runnable() {
+ UserHandle user = new UserHandle(ActivityManager.getCurrentUser());
+ TunerService.showResetRequest(getContext(), user, new Runnable() {
@Override
public void run() {
if (getActivity() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 338e178..70bba26 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -14,7 +14,6 @@
package com.android.systemui.tuner;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -51,25 +50,24 @@
void onTuningChanged(String key, String newValue);
}
- private static Context userContext(Context context) {
+ private static Context userContext(Context context, UserHandle user) {
try {
- return context.createPackageContextAsUser(context.getPackageName(), 0,
- new UserHandle(ActivityManager.getCurrentUser()));
+ return context.createPackageContextAsUser(context.getPackageName(), 0, user);
} catch (NameNotFoundException e) {
return context;
}
}
- public static final void setTunerEnabled(Context context, boolean enabled) {
- userContext(context).getPackageManager().setComponentEnabledSetting(
+ public static final void setTunerEnabled(Context context, UserHandle user, boolean enabled) {
+ userContext(context, user).getPackageManager().setComponentEnabledSetting(
new ComponentName(context, TunerActivity.class),
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
- public static final boolean isTunerEnabled(Context context) {
- return userContext(context).getPackageManager().getComponentEnabledSetting(
+ public static final boolean isTunerEnabled(Context context, UserHandle user) {
+ return userContext(context, user).getPackageManager().getComponentEnabledSetting(
new ComponentName(context, TunerActivity.class))
== PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}
@@ -83,7 +81,8 @@
}
}
- public static final void showResetRequest(final Context context, final Runnable onDisabled) {
+ public static final void showResetRequest(final Context context, UserHandle user,
+ final Runnable onDisabled) {
SystemUIDialog dialog = new SystemUIDialog(context);
dialog.setShowForAllUsers(true);
dialog.setMessage(R.string.remove_from_settings_prompt);
@@ -91,20 +90,20 @@
(OnClickListener) null);
dialog.setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // Tell the tuner (in main SysUI process) to clear all its settings.
- context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
- // Disable access to tuner.
- TunerService.setTunerEnabled(context, false);
- // Make them sit through the warning dialog again.
- Settings.Secure.putInt(context.getContentResolver(),
- TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
- if (onDisabled != null) {
- onDisabled.run();
- }
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Tell the tuner (in main SysUI process) to clear all its settings.
+ context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
+ // Disable access to tuner.
+ TunerService.setTunerEnabled(context, user, false);
+ // Make them sit through the warning dialog again.
+ Settings.Secure.putInt(context.getContentResolver(),
+ TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
+ if (onDisabled != null) {
+ onDisabled.run();
+ }
+ }
+ });
dialog.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index d9727a7..22f03e07 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -15,13 +15,13 @@
*/
package com.android.systemui.tuner;
-import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
@@ -37,7 +37,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.util.leak.LeakDetector;
@@ -81,7 +81,8 @@
private ContentResolver mContentResolver;
private int mCurrentUser;
- private CurrentUserTracker mUserTracker;
+ private UserTracker.Callback mCurrentUserTracker;
+ private UserTracker mUserTracker;
/**
*/
@@ -91,11 +92,13 @@
@Main Handler mainHandler,
LeakDetector leakDetector,
DemoModeController demoModeController,
- BroadcastDispatcher broadcastDispatcher) {
+ BroadcastDispatcher broadcastDispatcher,
+ UserTracker userTracker) {
mContext = context;
mContentResolver = mContext.getContentResolver();
mLeakDetector = leakDetector;
mDemoModeController = demoModeController;
+ mUserTracker = userTracker;
for (UserInfo user : UserManager.get(mContext).getUsers()) {
mCurrentUser = user.getUserHandle().getIdentifier();
@@ -104,21 +107,22 @@
}
}
- mCurrentUser = ActivityManager.getCurrentUser();
- mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
+ mCurrentUser = mUserTracker.getUserId();
+ mCurrentUserTracker = new UserTracker.Callback() {
@Override
- public void onUserSwitched(int newUserId) {
- mCurrentUser = newUserId;
+ public void onUserChanged(int newUser, Context userContext) {
+ mCurrentUser = newUser;
reloadAll();
reregisterAll();
}
};
- mUserTracker.startTracking();
+ mUserTracker.addCallback(mCurrentUserTracker,
+ new HandlerExecutor(mainHandler));
}
@Override
public void destroy() {
- mUserTracker.stopTracking();
+ mUserTracker.removeCallback(mCurrentUserTracker);
}
private void upgradeTuner(int oldVersion, int newVersion, Handler mainHandler) {
@@ -137,7 +141,7 @@
}
}
if (oldVersion < 2) {
- setTunerEnabled(mContext, false);
+ setTunerEnabled(mContext, mUserTracker.getUserHandle(), false);
}
// 3 Removed because of a revert.
if (oldVersion < 4) {
@@ -272,7 +276,7 @@
@Override
public void onChange(boolean selfChange, java.util.Collection<Uri> uris,
int flags, int userId) {
- if (userId == ActivityManager.getCurrentUser()) {
+ if (userId == mUserTracker.getUserId()) {
for (Uri u : uris) {
reloadSetting(u);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index f277b30..bde88b1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -17,7 +17,7 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.pip.tv.dagger.TvPipModule;
+import com.android.systemui.wmshell.TvPipModule;
import dagger.Binds;
import dagger.Module;
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index a6cd350..344f0d2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -27,7 +27,6 @@
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
-import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -93,10 +92,6 @@
}
/**
- * Creates the QuickStatusBarHeader.
- */
- QuickStatusBarHeader createQsHeader();
- /**
* Creates the QSFooterImpl.
*/
QSFooterImpl createQsFooter();
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 90b95ea..0d63324 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.wm.shell.pip.tv.PipNotification;
import java.util.Arrays;
@@ -34,8 +35,8 @@
public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP";
public static String GENERAL = "GEN";
public static String STORAGE = "DSK";
- public static String TVPIP = "TPP";
public static String BATTERY = "BAT";
+ public static String TVPIP = PipNotification.NOTIFICATION_CHANNEL_TVPIP;
public static String HINTS = "HNT";
public NotificationChannels(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index 3347cf6..603d423 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -46,6 +46,7 @@
private var measureAsConstraint: Boolean = false
private var currentState: TransitionViewState = TransitionViewState()
private var updateScheduled = false
+ private var isPreDrawApplicatorRegistered = false
private var desiredMeasureWidth = 0
private var desiredMeasureHeight = 0
@@ -74,6 +75,7 @@
override fun onPreDraw(): Boolean {
updateScheduled = false
viewTreeObserver.removeOnPreDrawListener(this)
+ isPreDrawApplicatorRegistered = false
applyCurrentState()
return true
}
@@ -94,6 +96,14 @@
}
}
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ if (isPreDrawApplicatorRegistered) {
+ viewTreeObserver.removeOnPreDrawListener(preDrawApplicator)
+ isPreDrawApplicatorRegistered = false
+ }
+ }
+
/**
* Apply the current state to the view and its widgets
*/
@@ -158,7 +168,10 @@
private fun applyCurrentStateOnPredraw() {
if (!updateScheduled) {
updateScheduled = true
- viewTreeObserver.addOnPreDrawListener(preDrawApplicator)
+ if (!isPreDrawApplicatorRegistered) {
+ viewTreeObserver.addOnPreDrawListener(preDrawApplicator)
+ isPreDrawApplicatorRegistered = true
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java
rename to packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index f094854..247baf8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -14,45 +14,38 @@
* limitations under the License.
*/
-package com.android.systemui.pip.tv.dagger;
+package com.android.systemui.wmshell;
-import android.app.Activity;
import android.content.Context;
+import android.os.Handler;
+import android.view.LayoutInflater;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.pip.tv.PipController;
-import com.android.systemui.pip.tv.PipMenuActivity;
-import com.android.systemui.pip.tv.PipNotification;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.tv.PipController;
+import com.android.wm.shell.pip.tv.PipControlsView;
+import com.android.wm.shell.pip.tv.PipControlsViewController;
+import com.android.wm.shell.pip.tv.PipNotification;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
/**
* Dagger module for TV Pip.
*/
-@Module(subcomponents = {TvPipComponent.class})
+@Module
public abstract class TvPipModule {
- /** Inject into PipMenuActivity. */
- @Binds
- @IntoMap
- @ClassKey(PipMenuActivity.class)
- public abstract Activity providePipMenuActivity(PipMenuActivity activity);
-
@SysUISingleton
@Provides
static Pip providePipController(Context context,
@@ -65,6 +58,21 @@
@SysUISingleton
@Provides
+ static PipControlsViewController providePipControlsViewContrller(
+ PipControlsView pipControlsView, PipController pipController,
+ LayoutInflater layoutInflater, Handler handler) {
+ return new PipControlsViewController(pipControlsView, pipController, layoutInflater,
+ handler);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipControlsView providePipControlsView(Context context) {
+ return new PipControlsView(context, null);
+ }
+
+ @SysUISingleton
+ @Provides
static PipNotification providePipNotification(Context context,
PipController pipController) {
return new PipNotification(context, pipController);
@@ -72,13 +80,13 @@
@SysUISingleton
@Provides
- static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ static PipBoundsHandler providePipBoundsHandler(Context context) {
return new PipBoundsHandler(context);
}
@SysUISingleton
@Provides
- static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ static PipTaskOrganizer providePipTaskOrganizer(Context context,
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 1e6a9e8..56efffc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -22,7 +22,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.tv.dagger.TvPipModule;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 250c592..b828535 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,8 +55,6 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.phone.PipUtils;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -73,6 +71,8 @@
import com.android.wm.shell.onehanded.OneHandedEvents;
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.phone.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogImpl;
import com.android.wm.shell.splitscreen.SplitScreen;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index dfb30b4..970d500 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -27,22 +27,25 @@
import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.pip.phone.PipAppOpsListener;
-import com.android.systemui.pip.phone.PipMediaController;
-import com.android.systemui.pip.phone.PipTouchHandler;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.animation.FlingAnimationUtils;
+import com.android.wm.shell.common.AnimationThread;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.onehanded.OneHanded;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PipAppOpsListener;
+import com.android.wm.shell.pip.phone.PipMediaController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
import dagger.BindsOptionalOf;
@@ -89,7 +92,7 @@
@SysUISingleton
@Provides
- static PipAppOpsListener providesPipAppOpsListener(Context context,
+ static PipAppOpsListener providePipAppOpsListener(Context context,
IActivityManager activityManager,
PipTouchHandler pipTouchHandler) {
return new PipAppOpsListener(context, activityManager, pipTouchHandler.getMotionHelper());
@@ -97,7 +100,7 @@
@SysUISingleton
@Provides
- static PipMediaController providesPipMediaController(Context context,
+ static PipMediaController providePipMediaController(Context context,
IActivityManager activityManager) {
return new PipMediaController(context, activityManager);
}
@@ -131,8 +134,10 @@
@SysUISingleton
@Provides
- static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue) {
- ShellTaskOrganizer organizer = new ShellTaskOrganizer(syncQueue);
+ static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue,
+ @Main Handler handler, TransactionPool transactionPool) {
+ ShellTaskOrganizer organizer = new ShellTaskOrganizer(syncQueue, transactionPool,
+ new HandlerExecutor(handler), AnimationThread.instance().getExecutor());
organizer.registerOrganizer();
return organizer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index b4852b2..61c3f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -22,25 +22,26 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.pip.phone.PipAppOpsListener;
-import com.android.systemui.pip.phone.PipController;
-import com.android.systemui.pip.phone.PipMediaController;
-import com.android.systemui.pip.phone.PipMenuActivityController;
-import com.android.systemui.pip.phone.PipTouchHandler;
-import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PipAppOpsListener;
+import com.android.wm.shell.pip.phone.PipController;
+import com.android.wm.shell.pip.phone.PipMediaController;
+import com.android.wm.shell.pip.phone.PipMenuActivityController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index d93cc05..e73ed80 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -53,6 +53,7 @@
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.media.AudioManager;
import android.os.Bundle;
@@ -132,7 +133,7 @@
@Mock
private FaceManager mFaceManager;
@Mock
- private List<FaceSensorProperties> mFaceSensorProperties;
+ private List<FaceSensorPropertiesInternal> mFaceSensorProperties;
@Mock
private BiometricManager mBiometricManager;
@Mock
@@ -177,13 +178,14 @@
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFaceManager.getSensorProperties()).thenReturn(mFaceSensorProperties);
+ when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties);
// IBiometricsFace@1.0 does not support detection, only authentication.
when(mFaceSensorProperties.isEmpty()).thenReturn(false);
- when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorProperties(0 /* id */,
- false /* supportsFaceDetection */, true /* supportsSelfIllumination */,
- 1 /* maxTemplatesAllowed */));
+ when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal(
+ 0 /* id */,
+ FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */,
+ false /* supportsFaceDetection */, true /* supportsSelfIllumination */));
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index d107f64..ab805f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -62,6 +62,7 @@
import com.android.systemui.R.dimen;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
@@ -88,6 +89,8 @@
private TunerService mTunerService;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private UserTracker mUserTracker;
@Before
public void setup() {
@@ -109,7 +112,7 @@
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
mScreenDecorations = spy(new ScreenDecorations(mContext, mMainHandler,
- mBroadcastDispatcher, mTunerService) {
+ mBroadcastDispatcher, mTunerService, mUserTracker) {
@Override
public void start() {
super.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 1e969c2..fa78d1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -36,6 +36,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -65,6 +66,8 @@
@Mock
private ModeSwitchesController mModeSwitchesController;
@Mock
+ private NavigationModeController mNavigationModeController;
+ @Mock
private IRemoteMagnificationAnimationCallback mAnimationCallback;
private IWindowMagnificationConnection mIWindowMagnificationConnection;
private WindowMagnification mWindowMagnification;
@@ -79,7 +82,8 @@
}).when(mAccessibilityManager).setWindowMagnificationConnection(
any(IWindowMagnificationConnection.class));
mWindowMagnification = new WindowMagnification(getContext(),
- getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
+ getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
+ mNavigationModeController);
mWindowMagnification.mWindowMagnificationAnimationController =
mWindowMagnificationAnimationController;
mWindowMagnification.requestWindowMagnificationConnection(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index c6440f4..5f2fd69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility;
import static android.view.Choreographer.FrameCallback;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import static org.hamcrest.Matchers.containsString;
@@ -28,6 +29,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -294,4 +296,15 @@
assertTrue(
mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_left, null));
}
+
+ @Test
+ public void onNavigationModeChanged_updateMirrorViewLayout() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.onNavigationModeChanged(NAV_BAR_MODE_GESTURAL);
+ });
+
+ verify(mWindowManager).updateViewLayout(eq(mMirrorView), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 936558b..4a0e216 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -35,6 +35,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -53,6 +54,8 @@
private AccessibilityManager mAccessibilityManager;
@Mock
private ModeSwitchesController mModeSwitchesController;
+ @Mock
+ private NavigationModeController mNavigationModeController;
private CommandQueue mCommandQueue;
private WindowMagnification mWindowMagnification;
@@ -63,7 +66,8 @@
mCommandQueue = new CommandQueue(getContext());
mWindowMagnification = new WindowMagnification(getContext(),
- getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
+ getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
+ mNavigationModeController);
mWindowMagnification.start();
}
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 f6b39c2..e0420ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -49,6 +49,7 @@
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -120,14 +121,15 @@
when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
- FingerprintSensorProperties prop = new FingerprintSensorProperties(1 /* sensorId */,
+ FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+ 1 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequireHardwareAuthToken */);
- List<FingerprintSensorProperties> props = new ArrayList<>();
+ List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
props.add(prop);
- when(mFingerprintManager.getSensorProperties()).thenReturn(props);
+ when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mAuthController = new TestableAuthController(context, mCommandQueue,
mStatusBarStateController, mActivityTaskManager, mFingerprintManager,
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 7df9f1f..99e39b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -30,6 +30,7 @@
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -109,13 +110,13 @@
public void setUp() {
setUpResources();
when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
- final List<FingerprintSensorProperties> props = new ArrayList<>();
- props.add(new FingerprintSensorProperties(TEST_UDFPS_SENSOR_ID,
+ final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(new FingerprintSensorPropertiesInternal(TEST_UDFPS_SENSOR_ID,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */));
- when(mFingerprintManager.getSensorProperties()).thenReturn(props);
+ when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mSystemSettings = new FakeSettings();
mFgExecutor = new FakeExecutor(new FakeSystemClock());
mUdfpsController = new UdfpsController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2f8d3f6..08ccd854 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -91,8 +91,8 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import com.google.common.collect.ImmutableList;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index cfbd398..1eaa6a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -90,9 +90,9 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.InjectionInflationController;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index ec9571a..87ea22a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -35,8 +35,9 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.wmshell.WindowManagerShellWrapper;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.FloatingContentCoordinator;
+
/**
* Testable BubbleController subclass that immediately synchronizes surfaces.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index cc62a2f..9242ce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -33,7 +33,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
-import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index bb003ee..0a81c38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -27,6 +27,7 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -61,6 +62,8 @@
@Mock
private lateinit var mockControlsController: ControlsController
+ @Mock(stubOnly = true)
+ private lateinit var mockUserTracker: UserTracker
@Captor
private lateinit var subscriberCaptor: ArgumentCaptor<IControlsSubscriber.Stub>
@@ -82,9 +85,10 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
providers.clear()
+ `when`(mockUserTracker.userHandle).thenReturn(user)
controller = TestableControlsBindingControllerImpl(
- mContext, executor, Lazy { mockControlsController })
+ mContext, executor, Lazy { mockControlsController }, mockUserTracker)
}
@After
@@ -364,8 +368,9 @@
class TestableControlsBindingControllerImpl(
context: Context,
executor: DelayableExecutor,
- lazyController: Lazy<ControlsController>
-) : ControlsBindingControllerImpl(context, executor, lazyController) {
+ lazyController: Lazy<ControlsController>,
+ userTracker: UserTracker
+) : ControlsBindingControllerImpl(context, executor, lazyController, userTracker) {
companion object {
val providers = mutableListOf<ControlsProviderLifecycleManager>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 45262c7..f6c836a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
@@ -82,6 +83,8 @@
private lateinit var broadcastDispatcher: BroadcastDispatcher
@Mock
private lateinit var listingController: ControlsListingController
+ @Mock(stubOnly = true)
+ private lateinit var userTracker: UserTracker
@Captor
private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo>
@@ -143,6 +146,8 @@
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 1, otherUser)
+ `when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
+
delayableExecutor = FakeExecutor(FakeSystemClock())
val wrapper = object : ContextWrapper(mContext) {
@@ -162,7 +167,8 @@
listingController,
broadcastDispatcher,
Optional.of(persistenceWrapper),
- mock(DumpManager::class.java)
+ mock(DumpManager::class.java),
+ userTracker
)
controller.auxiliaryPersistenceWrapper = auxiliaryPersistenceWrapper
@@ -217,7 +223,8 @@
listingController,
broadcastDispatcher,
Optional.of(persistenceWrapper),
- mock(DumpManager::class.java)
+ mock(DumpManager::class.java),
+ userTracker
)
assertEquals(listOf(TEST_STRUCTURE_INFO), controller_other.getFavorites())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 841b255..db41d8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -26,6 +26,7 @@
import com.android.settingslib.applications.ServiceListing
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
@@ -66,6 +67,8 @@
private lateinit var serviceInfo: ServiceInfo
@Mock
private lateinit var serviceInfo2: ServiceInfo
+ @Mock(stubOnly = true)
+ private lateinit var userTracker: UserTracker
private var componentName = ComponentName("pkg1", "class1")
private var componentName2 = ComponentName("pkg2", "class2")
@@ -86,6 +89,7 @@
`when`(serviceInfo.componentName).thenReturn(componentName)
`when`(serviceInfo2.componentName).thenReturn(componentName2)
+ `when`(userTracker.userId).thenReturn(user)
val wrapper = object : ContextWrapper(mContext) {
override fun createContextAsUser(user: UserHandle, flags: Int): Context {
@@ -93,7 +97,7 @@
}
}
- controller = ControlsListingControllerImpl(wrapper, executor, { mockSL })
+ controller = ControlsListingControllerImpl(wrapper, executor, { mockSL }, userTracker)
verify(mockSL).addCallback(capture(serviceListingCallbackCaptor))
}
@@ -121,7 +125,7 @@
`when`(mockServiceListing.reload()).then {
callback?.onServicesReloaded(listOf(serviceInfo))
}
- ControlsListingControllerImpl(mContext, exec, { mockServiceListing })
+ ControlsListingControllerImpl(mContext, exec, { mockServiceListing }, userTracker)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index ca328fb..9ebb587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -36,6 +36,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.ShadeController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,6 +74,11 @@
when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
}
+ @After
+ public void tearDown() {
+ mMediaOutputDialog.dismissDialog();
+ }
+
@Test
public void getStopButtonVisibility_remoteDevice_returnVisible() {
mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
index 1f10d01..cb17829 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -16,15 +16,14 @@
package com.android.systemui.privacy
-import android.os.UserManager
import android.provider.DeviceConfig
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.appops.AppOpsController
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.concurrency.FakeExecutor
@@ -62,11 +61,9 @@
@Mock
private lateinit var callback: PrivacyItemController.Callback
@Mock
- private lateinit var userManager: UserManager
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
private lateinit var dumpManager: DumpManager
+ @Mock
+ private lateinit var userTracker: UserTracker
private lateinit var privacyItemController: PrivacyItemController
private lateinit var executor: FakeExecutor
@@ -77,9 +74,8 @@
appOpsController,
executor,
executor,
- broadcastDispatcher,
deviceConfigProxy,
- userManager,
+ userTracker,
dumpManager
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 0a079b1..16a1105 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -18,10 +18,8 @@
import android.app.ActivityManager
import android.app.AppOpsManager
-import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserHandle
-import android.os.UserManager
import android.provider.DeviceConfig
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
@@ -30,8 +28,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.concurrency.FakeExecutor
@@ -52,6 +50,7 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -84,9 +83,7 @@
@Mock
private lateinit var callback: PrivacyItemController.Callback
@Mock
- private lateinit var userManager: UserManager
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
+ private lateinit var userTracker: UserTracker
@Mock
private lateinit var dumpManager: DumpManager
@Captor
@@ -103,9 +100,8 @@
appOpsController,
executor,
executor,
- broadcastDispatcher,
deviceConfigProxy,
- userManager,
+ userTracker,
dumpManager
)
}
@@ -119,11 +115,7 @@
// Listen to everything by default
changeAll(true)
- doReturn(listOf(object : UserInfo() {
- init {
- id = CURRENT_USER_ID
- }
- })).`when`(userManager).getProfiles(anyInt())
+ `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(CURRENT_USER_ID, "", 0)))
privacyItemController = PrivacyItemController()
}
@@ -163,37 +155,26 @@
}
@Test
- fun testRegisterReceiver_allUsers() {
+ fun testRegisterCallback() {
privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(broadcastDispatcher, atLeastOnce()).registerReceiver(
- eq(privacyItemController.userSwitcherReceiver), any(), eq(null), eq(UserHandle.ALL))
- verify(broadcastDispatcher, never())
- .unregisterReceiver(eq(privacyItemController.userSwitcherReceiver))
+ verify(userTracker, atLeastOnce()).addCallback(
+ eq(privacyItemController.userTrackerCallback), any())
+ verify(userTracker, never()).removeCallback(eq(privacyItemController.userTrackerCallback))
}
@Test
- fun testReceiver_ACTION_USER_FOREGROUND() {
- privacyItemController.userSwitcherReceiver.onReceive(context,
- Intent(Intent.ACTION_USER_SWITCHED))
+ fun testCallback_userChanged() {
+ privacyItemController.userTrackerCallback.onUserChanged(0, mContext)
executor.runAllReady()
- verify(userManager).getProfiles(anyInt())
+ verify(userTracker).userProfiles
}
@Test
- fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() {
- privacyItemController.userSwitcherReceiver.onReceive(context,
- Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE))
+ fun testReceiver_profilesChanged() {
+ privacyItemController.userTrackerCallback.onProfilesChanged(emptyList())
executor.runAllReady()
- verify(userManager).getProfiles(anyInt())
- }
-
- @Test
- fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() {
- privacyItemController.userSwitcherReceiver.onReceive(context,
- Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE))
- executor.runAllReady()
- verify(userManager).getProfiles(anyInt())
+ verify(userTracker).userProfiles
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index d4688d7..99f2d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -14,30 +14,40 @@
package com.android.systemui.qs;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -47,19 +57,46 @@
private QSFooterImpl mFooter;
private ActivityStarter mActivityStarter;
private DeviceProvisionedController mDeviceProvisionedController;
+ private UserInfoController mUserInfoController;
+ private UserTracker mUserTracker;
+ @Mock
+ private ClipboardManager mClipboardManager;
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
mDeviceProvisionedController = mDependency.injectMockDependency(
DeviceProvisionedController.class);
+ mUserInfoController = mDependency.injectMockDependency(UserInfoController.class);
+ mUserTracker = mDependency.injectMockDependency(UserTracker.class);
+
+ mContext.addMockSystemService(ClipboardManager.class, mClipboardManager);
+
+ when(mUserTracker.getUserContext()).thenReturn(mContext);
+
TestableLooper.get(this).runWithLooper(
() -> mFooter = (QSFooterImpl) LayoutInflater.from(mContext).inflate(
R.layout.qs_footer_impl, null));
}
@Test
+ public void testBuildTextCopy() {
+ TextView buildTextView = mFooter.requireViewById(R.id.build);
+ CharSequence buildText = "TEST";
+ buildTextView.setText(buildText);
+ buildTextView.setLongClickable(true);
+
+ buildTextView.performLongClick();
+
+ ArgumentCaptor<ClipData> captor = ArgumentCaptor.forClass(ClipData.class);
+ verify(mClipboardManager).setPrimaryClip(captor.capture());
+ assertThat(captor.getValue().getItemAt(0).getText()).isEqualTo(buildText);
+ }
+
+ @Test
@Ignore("failing")
public void testSettings_UserNotSetup() {
View settingsButton = mFooter.findViewById(id.settings_button);
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 b46c6ef..e472cb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -37,7 +37,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.CarrierText;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -45,6 +44,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoTileManager;
@@ -107,7 +107,7 @@
mock(PluginManager.class), mock(TunerService.class),
() -> mock(AutoTileManager.class), mock(DumpManager.class),
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
- mock(QSLogger.class), mock(UiEventLogger.class));
+ mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class));
qs.setHost(host);
qs.setListening(true);
@@ -115,11 +115,6 @@
qs.setListening(false);
processAllMessages();
-
- // Manually push header through detach so it can handle standard cleanup it does on
- // removed from window.
- ((QuickStatusBarHeader) qs.getView().findViewById(R.id.header)).onDetachedFromWindow();
-
host.destroy();
processAllMessages();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index cb3a048..4b7a268 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -38,7 +38,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -49,7 +48,7 @@
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.util.animation.DisappearParameters;
import com.android.systemui.util.animation.UniqueObjectHostView;
@@ -93,11 +92,9 @@
@Mock
private MediaHost mMediaHost;
@Mock
- private LocalBluetoothManager mLocalBluetoothManager;
- @Mock
private ActivityStarter mActivityStarter;
- @Mock
- private NotificationEntryManager mEntryManager;
+ @Mock(stubOnly = true)
+ private UserTracker mUserTracker;
private UiEventLoggerFake mUiEventLogger;
@Before
@@ -117,7 +114,7 @@
mTestableLooper.runWithLooper(() -> {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
- mQSLogger, mMediaHost, mUiEventLogger);
+ mQSLogger, mMediaHost, mUiEventLogger, mUserTracker);
mQsPanel.onFinishInflate();
// Provides a parent with non-zero size for QSPanel
mParentView = new FrameLayout(mContext);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 417b19f..fd1866b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -17,7 +17,6 @@
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -25,7 +24,6 @@
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.UserManager;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -42,6 +40,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.SecurityController;
import org.junit.Before;
@@ -73,20 +72,20 @@
private TestableImageView mFooterIcon;
private QSSecurityFooter mFooter;
private SecurityController mSecurityController = mock(SecurityController.class);
- private UserManager mUserManager;
+ private UserTracker mUserTracker;
@Before
public void setUp() {
mDependency.injectTestDependency(SecurityController.class, mSecurityController);
mDependency.injectTestDependency(Dependency.BG_LOOPER,
TestableLooper.get(this).getLooper());
+ mUserTracker = mock(UserTracker.class);
+ when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class)
.build());
- mUserManager = Mockito.mock(UserManager.class);
- mContext.addMockSystemService(Context.USER_SERVICE, mUserManager);
- mFooter = new QSSecurityFooter(null, mContext);
+ mFooter = new QSSecurityFooter(null, mContext, mUserTracker);
mRootView = (ViewGroup) mFooter.getView();
mFooterText = mRootView.findViewById(R.id.footer_text);
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
@@ -141,7 +140,7 @@
when(mSecurityController.getDeviceOwnerOrganizationName()).thenReturn(null);
final UserInfo mockUserInfo = Mockito.mock(UserInfo.class);
when(mockUserInfo.isDemo()).thenReturn(true);
- when(mUserManager.getUserInfo(anyInt())).thenReturn(mockUserInfo);
+ when(mUserTracker.getUserInfo()).thenReturn(mockUserInfo);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_DEMO_MODE, 1);
mFooter.refreshState();
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 c8e1a74..452ff4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -55,6 +55,7 @@
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
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.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -110,6 +111,8 @@
private CustomTile mCustomTile;
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private UserTracker mUserTracker;
private Handler mHandler;
private TestableLooper mLooper;
@@ -122,7 +125,7 @@
mHandler = new Handler(mLooper.getLooper());
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
- mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger);
+ mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker);
setUpTileFactory();
Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
@@ -301,10 +304,10 @@
PluginManager pluginManager, TunerService tunerService,
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger, UserTracker userTracker) {
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
tunerService, autoTiles, dumpManager, broadcastDispatcher,
- Optional.of(statusBar), qsLogger, uiEventLogger);
+ Optional.of(statusBar), qsLogger, uiEventLogger, userTracker);
}
@Override
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 2ef7c65..a2ffb84 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,6 +55,7 @@
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.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -103,6 +104,8 @@
private QSTileHost mQSTileHost;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private UserTracker mUserTracker;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -133,7 +136,7 @@
FakeSystemClock clock = new FakeSystemClock();
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
- mTileQueryHelper = new TileQueryHelper(mContext, mMainExecutor, mBgExecutor);
+ mTileQueryHelper = new TileQueryHelper(mContext, mUserTracker, mMainExecutor, mBgExecutor);
mTileQueryHelper.setListener(mListener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
index 683e8f4..6a9d9fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
@@ -22,11 +22,13 @@
import android.content.ComponentName;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.UserTracker;
import org.junit.After;
import org.junit.Before;
@@ -44,6 +46,7 @@
private HandlerThread mThread;
private Handler mHandler;
private TileServiceManager mTileServiceManager;
+ private UserTracker mUserTracker;
@Before
public void setUp() throws Exception {
@@ -51,13 +54,18 @@
mThread.start();
mHandler = Handler.createAsync(mThread.getLooper());
mTileServices = Mockito.mock(TileServices.class);
+ mUserTracker = Mockito.mock(UserTracker.class);
+ Mockito.when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ Mockito.when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+
Mockito.when(mTileServices.getContext()).thenReturn(mContext);
mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
Mockito.when(mTileLifecycle.isActiveTile()).thenReturn(false);
ComponentName componentName = new ComponentName(mContext,
TileServiceManagerTest.class);
Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
- mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+ mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mUserTracker,
+ mTileLifecycle);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 53ed4cf..2a3bc31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -46,6 +46,7 @@
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -92,6 +93,8 @@
private QSLogger mQSLogger;
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private UserTracker mUserTracker;
@Before
public void setUp() throws Exception {
@@ -110,8 +113,10 @@
mock(BroadcastDispatcher.class),
Optional.of(mStatusBar),
mQSLogger,
- mUiEventLogger);
- mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher);
+ mUiEventLogger,
+ mUserTracker);
+ mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
+ mUserTracker);
}
@After
@@ -186,8 +191,8 @@
private class TestTileServices extends TileServices {
TestTileServices(QSTileHost host, Looper looper,
- BroadcastDispatcher broadcastDispatcher) {
- super(host, looper, broadcastDispatcher);
+ BroadcastDispatcher broadcastDispatcher, UserTracker userTracker) {
+ super(host, looper, broadcastDispatcher, userTracker);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
index 727f91c..0c3db57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -36,11 +36,11 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.pip.Pip;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
new file mode 100644
index 0000000..16eb1d9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.commandline
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+
+import com.android.systemui.SysuiTestCase
+
+import org.mockito.ArgumentMatchers.anyList
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.util.concurrent.Executor
+
+private fun <T> anyObject(): T {
+ return Mockito.anyObject<T>()
+}
+
+private fun <T : Any> safeEq(value: T): T = eq(value) ?: value
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class CommandRegistryTest : SysuiTestCase() {
+ lateinit var registry: CommandRegistry
+ val inLineExecutor = object : Executor {
+ override fun execute(command: Runnable) {
+ command.run()
+ }
+ }
+
+ val writer: PrintWriter = PrintWriter(StringWriter())
+
+ @Before
+ fun setup() {
+ registry = CommandRegistry(context, inLineExecutor)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testRegisterCommand_throwsWhenAlreadyRegistered() {
+ registry.registerCommand(COMMAND) { FakeCommand() }
+ // Should throw when registering the same command twice
+ registry.registerCommand(COMMAND) { FakeCommand() }
+ }
+
+ @Test
+ fun testOnShellCommand() {
+ var fakeCommand = mock(Command::class.java)
+ registry.registerCommand(COMMAND) { fakeCommand }
+ registry.onShellCommand(writer, arrayOf(COMMAND))
+ verify(fakeCommand).execute(anyObject(), anyList())
+ }
+
+ @Test
+ fun testArgsPassedToShellCommand() {
+ var fakeCommand = mock(Command::class.java)
+ registry.registerCommand(COMMAND) { fakeCommand }
+ registry.onShellCommand(writer, arrayOf(COMMAND, "arg1", "arg2", "arg3"))
+ verify(fakeCommand).execute(anyObject(), safeEq(listOf("arg1", "arg2", "arg3")))
+ }
+
+ class FakeCommand() : Command {
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ }
+
+ override fun help(pw: PrintWriter) {
+ }
+ }
+}
+
+private const val COMMAND = "test_command"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 0c2361a..be836d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -20,11 +20,13 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Handler;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -35,6 +37,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
import org.junit.Before;
@@ -52,10 +55,13 @@
private TestableLooper mTestableLooper;
@Mock private AppOpsController mAppOpsController;
+ @Mock private UserTracker mUserTracker;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
mTestableLooper = TestableLooper.get(this);
mLocationController = spy(new LocationControllerImpl(mContext,
@@ -63,7 +69,8 @@
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
mock(BroadcastDispatcher.class),
- mock(BootCompleteCache.class)));
+ mock(BootCompleteCache.class),
+ mUserTracker));
mTestableLooper.processAllMessages();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index e88b514..4fb85ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -17,9 +17,15 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.RemoteInput;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ShortcutManager;
@@ -130,8 +136,18 @@
private UserHandle getTargetInputMethodUser(UserHandle fromUser, UserHandle toUser)
throws Exception {
+ /**
+ * RemoteInputView, Icon, and Bubble have the situation need to handle the other user.
+ * SystemUI cross multiple user but this test(com.android.systemui.tests) doesn't cross
+ * multiple user. It needs some of mocking multiple user environment to ensure the
+ * createContextAsUser without throwing IllegalStateException.
+ */
+ Context contextSpy = spy(mContext);
+ doReturn(contextSpy).when(contextSpy).createContextAsUser(any(), anyInt());
+ doReturn(toUser.getIdentifier()).when(contextSpy).getUserId();
+
NotificationTestHelper helper = new NotificationTestHelper(
- mContext,
+ contextSpy,
mDependency,
TestableLooper.get(this));
ExpandableNotificationRow row = helper.createRow(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
index 8eecde1..31848a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
@@ -5,6 +5,7 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.common.FloatingContentCoordinator
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index f3cdbf7..c085689 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -21,6 +21,7 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.app.KeyguardManager;
@@ -167,6 +168,45 @@
AccessibilityManager.FLAG_CONTENT_CONTROLS);
}
+ @Test
+ public void testVibrateOnRingerChangedToVibrate() {
+ final State initialSilentState = new State();
+ initialSilentState.ringerModeInternal = AudioManager.RINGER_MODE_SILENT;
+
+ final State vibrateState = new State();
+ vibrateState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE;
+
+ // change ringer to silent
+ mDialog.onStateChangedH(initialSilentState);
+
+ // expected: shouldn't call vibrate yet
+ verify(mController, never()).vibrate(any());
+
+ // changed ringer to vibrate
+ mDialog.onStateChangedH(vibrateState);
+
+ // expected: vibrate device
+ verify(mController).vibrate(any());
+ }
+
+ @Test
+ public void testNoVibrateOnRingerInitialization() {
+ final State initialUnsetState = new State();
+ initialUnsetState.ringerModeInternal = -1;
+
+ // ringer not initialized yet:
+ mDialog.onStateChangedH(initialUnsetState);
+
+ final State vibrateState = new State();
+ vibrateState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE;
+
+ // changed ringer to vibrate
+ mDialog.onStateChangedH(vibrateState);
+
+ // shouldn't call vibrate
+ verify(mController, never()).vibrate(any());
+ }
+
/*
@Test
public void testContentDescriptions() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 0b75950..a5fbf19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -36,8 +36,6 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.pip.Pip;
-import com.android.systemui.pip.phone.PipTouchHandler;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -49,6 +47,8 @@
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -70,6 +70,7 @@
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock ActivityManagerWrapper mActivityManagerWrapper;
@Mock DisplayImeController mDisplayImeController;
+ @Mock InputConsumerController mMockInputConsumerController;
@Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@Mock SysUiState mSysUiState;
@@ -112,17 +113,22 @@
@Test
public void nonPipDevice_shouldNotInitPip() {
- TestableContext spiedContext = spy(mContext);
- when(mMockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
- when(spiedContext.getPackageManager()).thenReturn(mMockPackageManager);
- final WMShell nonPipWMShell = new WMShell(spiedContext, mCommandQueue,
- mConfigurationController, mInputConsumerController, mKeyguardUpdateMonitor,
+ final TestableContext nonPipContext = getNonPipFeatureContext();
+ final WMShell nonPipWMShell = new WMShell(nonPipContext, mCommandQueue,
+ mConfigurationController, mMockInputConsumerController, mKeyguardUpdateMonitor,
mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
Optional.of(mOneHanded), mTaskOrganizer, mProtoTracer);
nonPipWMShell.initPip(mPip);
verify(mCommandQueue, never()).addCallback(any());
+ verify(mKeyguardUpdateMonitor, never()).registerCallback(any());
+ verify(mConfigurationController, never()).addCallback(any());
+ verify(mSysUiState, never()).addCallback(any());
+ verify(mActivityManagerWrapper, never()).registerTaskStackListener(any());
+ verify(mMockInputConsumerController, never()).setInputListener(any());
+ verify(mMockInputConsumerController, never()).setRegistrationListener(any());
+ verify(mPip, never()).registerSessionListenerForCurrentUser();
}
@Test
@@ -151,4 +157,11 @@
OneHandedGestureHandler.OneHandedGestureEventCallback.class));
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
}
+
+ TestableContext getNonPipFeatureContext() {
+ TestableContext spiedContext = spy(mContext);
+ when(mMockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
+ when(spiedContext.getPackageManager()).thenReturn(mMockPackageManager);
+ return spiedContext;
+ }
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 915c2f6..613d28b 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -102,6 +102,7 @@
],
libs: [
"framework-tethering",
+ "framework-wifi",
],
jarjar_rules: "jarjar-rules.txt",
optimize: {
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
index 084743d..73fc833 100644
--- a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -25,6 +25,7 @@
import static android.system.OsConstants.SOCK_RAW;
import android.net.util.InterfaceParams;
+import android.net.util.PacketReader;
import android.net.util.SocketUtils;
import android.net.util.TetheringUtils;
import android.os.Handler;
@@ -32,8 +33,6 @@
import android.system.Os;
import android.util.Log;
-import com.android.net.module.util.PacketReader;
-
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Inet6Address;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index 33b9d00..da5f25b 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -28,6 +28,7 @@
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.net.netlink.NetlinkSocket;
+import android.net.netlink.StructNfGenMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
@@ -41,11 +42,12 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -66,11 +68,12 @@
private static final String NO_IPV4_ADDRESS = "";
private static final String NO_IPV4_GATEWAY = "";
// Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
- private static final int NF_NETLINK_CONNTRACK_NEW = 1;
- private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
- private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
+ public static final int NF_NETLINK_CONNTRACK_NEW = 1;
+ public static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
+ public static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
// Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
public static final short NFNL_SUBSYS_CTNETLINK = 1;
+ public static final short IPCTNL_MSG_CT_NEW = 0;
public static final short IPCTNL_MSG_CT_GET = 1;
private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
@@ -237,7 +240,7 @@
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
if (h1 == null) return false;
- sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
+ sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
(short) (NLM_F_REQUEST | NLM_F_DUMP));
final NativeHandle h2 = mDeps.createConntrackSocket(
@@ -267,16 +270,23 @@
}
@VisibleForTesting
- public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
- final int length = StructNlMsgHdr.STRUCT_SIZE;
+ public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
+ final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
final byte[] msg = new byte[length];
- final StructNlMsgHdr nlh = new StructNlMsgHdr();
final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ final StructNlMsgHdr nlh = new StructNlMsgHdr();
nlh.nlmsg_len = length;
nlh.nlmsg_type = type;
nlh.nlmsg_flags = flags;
- nlh.nlmsg_seq = 1;
+ nlh.nlmsg_seq = 0;
nlh.pack(byteBuffer);
+
+ // Header needs to be added to buffer since a generic netlink request is being sent.
+ final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET);
+ nfh.pack(byteBuffer);
+
try {
NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
NETLINK_MESSAGE_TIMEOUT_MS);
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index fd9e360..b285849 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,7 @@
*/
package com.android.networkstack.tethering;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static java.util.Arrays.asList;
@@ -23,7 +24,6 @@
import android.net.ConnectivityManager;
import android.net.IpPrefix;
import android.net.LinkAddress;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.ip.IpServer;
import android.net.util.PrefixUtils;
@@ -90,16 +90,24 @@
/**
* Record a new upstream IpPrefix which may conflict with tethering downstreams.
- * The downstreams will be notified if a conflict is found.
+ * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called,
+ * UpstreamNetworkState must have an already populated LinkProperties.
*/
- public void updateUpstreamPrefix(final Network network, final LinkProperties lp) {
- final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses());
- if (ipv4Prefixes.isEmpty()) {
- removeUpstreamPrefix(network);
+ public void updateUpstreamPrefix(final UpstreamNetworkState ns) {
+ // Do not support VPN as upstream
+ if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ removeUpstreamPrefix(ns.network);
return;
}
- mUpstreamPrefixMap.put(network, ipv4Prefixes);
+ final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(
+ ns.linkProperties.getAllLinkAddresses());
+ if (ipv4Prefixes.isEmpty()) {
+ removeUpstreamPrefix(ns.network);
+ return;
+ }
+
+ mUpstreamPrefixMap.put(ns.network, ipv4Prefixes);
handleMaybePrefixConflict(ipv4Prefixes);
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 64d5025..474f4e8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1678,14 +1678,6 @@
}
}
- private void addUpstreamPrefixes(final UpstreamNetworkState ns) {
- mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties);
- }
-
- private void removeUpstreamPrefixes(final UpstreamNetworkState ns) {
- mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
- }
-
@VisibleForTesting
void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
@@ -1696,10 +1688,10 @@
final UpstreamNetworkState ns = (UpstreamNetworkState) o;
switch (arg1) {
case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- addUpstreamPrefixes(ns);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(ns);
break;
case UpstreamNetworkMonitor.EVENT_ON_LOST:
- removeUpstreamPrefixes(ns);
+ mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
break;
}
diff --git a/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java b/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java
new file mode 100644
index 0000000..57c28fc
--- /dev/null
+++ b/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.networkstack.tethering;
+
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+
+import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_GET;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.netlink.StructNlMsgHdr;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.NativeHandle;
+import android.system.Os;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConntrackSocketTest {
+ private static final long TIMEOUT = 500;
+
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private final SharedLog mLog = new SharedLog("privileged-test");
+
+ private OffloadHardwareInterface mOffloadHw;
+ private OffloadHardwareInterface.Dependencies mDeps;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mHandlerThread = new HandlerThread(getClass().getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
+ // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
+ if (Looper.myLooper() == null) Looper.prepare();
+
+ mDeps = new OffloadHardwareInterface.Dependencies(mLog);
+ mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps);
+ }
+
+ @Test
+ public void testIpv4ConntrackSocket() throws Exception {
+ // Set up server and connect.
+ final InetSocketAddress anyAddress = new InetSocketAddress(
+ InetAddress.getByName("127.0.0.1"), 0);
+ final ServerSocket serverSocket = new ServerSocket();
+ serverSocket.bind(anyAddress);
+ final SocketAddress theAddress = serverSocket.getLocalSocketAddress();
+
+ // Make a connection to the server.
+ final Socket socket = new Socket();
+ socket.connect(theAddress);
+ final Socket acceptedSocket = serverSocket.accept();
+
+ final NativeHandle handle = mDeps.createConntrackSocket(
+ NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
+ mOffloadHw.sendIpv4NfGenMsg(handle,
+ (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
+ (short) (NLM_F_REQUEST | NLM_F_DUMP));
+
+ boolean foundConntrackEntry = false;
+ ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_RECV_BUFSIZE);
+ buffer.order(ByteOrder.nativeOrder());
+
+ try {
+ while (Os.read(handle.getFileDescriptor(), buffer) > 0) {
+ buffer.flip();
+
+ // TODO: ConntrackMessage should get a parse API like StructNlMsgHdr
+ // so we can confirm that the conntrack added is for the TCP connection above.
+ final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(buffer);
+ assertNotNull(nlmsghdr);
+
+ // As long as 1 conntrack entry is found test case will pass, even if it's not
+ // the from the TCP connection above.
+ if (nlmsghdr.nlmsg_type == ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW)) {
+ foundConntrackEntry = true;
+ break;
+ }
+ }
+ } finally {
+ socket.close();
+ serverSocket.close();
+ }
+ assertTrue("Did not receive any NFNL_SUBSYS_CTNETLINK/IPCTNL_MSG_CT_NEW message",
+ foundConntrackEntry);
+ }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
index c543fad..38b19dd 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -17,8 +17,9 @@
package com.android.networkstack.tethering;
import static android.net.util.TetheringUtils.uint16;
-import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.SOCK_STREAM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -35,14 +36,15 @@
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.netlink.StructNfGenMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.NativeHandle;
import android.os.test.TestLooper;
import android.system.ErrnoException;
-import android.system.OsConstants;
import android.system.Os;
+import android.system.OsConstants;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -55,8 +57,8 @@
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
-import java.io.OutputStream;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
@RunWith(AndroidJUnit4.class)
@@ -218,7 +220,7 @@
}
@Test
- public void testNetlinkMessage() throws Exception {
+ public void testSendIpv4NfGenMsg() throws Exception {
FileDescriptor writeSocket = new FileDescriptor();
FileDescriptor readSocket = new FileDescriptor();
try {
@@ -229,17 +231,25 @@
}
when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
- mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
+ mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS);
- ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
+ ByteBuffer buffer = ByteBuffer.allocate(9823); // Arbitrary value > expectedLen.
+ buffer.order(ByteOrder.nativeOrder());
+
int read = Os.read(readSocket, buffer);
+ final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
+ assertEquals(expectedLen, read);
buffer.flip();
- assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
+ assertEquals(expectedLen, buffer.getInt());
assertEquals(TEST_TYPE, buffer.getShort());
assertEquals(TEST_FLAGS, buffer.getShort());
- assertEquals(1 /* seq */, buffer.getInt());
+ assertEquals(0 /* seq */, buffer.getInt());
assertEquals(0 /* pid */, buffer.getInt());
+ assertEquals(AF_INET, buffer.get()); // nfgen_family
+ assertEquals(0 /* error */, buffer.get()); // version
+ assertEquals(0 /* error */, buffer.getShort()); // res_id
+ assertEquals(expectedLen, buffer.position());
}
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 8e93c2e..7b6632c 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,10 @@
*/
package com.android.networkstack.tethering;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
@@ -30,13 +34,12 @@
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.ip.IpServer;
-import android.net.util.NetworkConstants;
import android.net.util.PrefixUtils;
import androidx.test.filters.SmallTest;
@@ -48,13 +51,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class PrivateAddressCoordinatorTest {
- private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
- private static final String TEST_WIFI_IFNAME = "test_wlan0";
+ private static final String TEST_IFNAME = "test0";
@Mock private IpServer mHotspotIpServer;
@Mock private IpServer mUsbIpServer;
@@ -69,7 +69,8 @@
private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
- private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
+ private final Network mVpnNetwork = new Network(3);
+ private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork};
private void setUpIpServers() throws Exception {
when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
@@ -184,33 +185,25 @@
assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix);
}
- private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6,
- boolean isMobile) {
- final String testIface;
- final String testIpv4Address;
- if (isMobile) {
- testIface = TEST_MOBILE_IFNAME;
- testIpv4Address = "10.0.0.1";
- } else {
- testIface = TEST_WIFI_IFNAME;
- testIpv4Address = "192.168.43.5";
- }
-
+ private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
+ final LinkAddress v4Addr, final LinkAddress v6Addr, final NetworkCapabilities cap) {
final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(testIface);
+ prop.setInterfaceName(TEST_IFNAME);
+ if (v4Addr != null) prop.addLinkAddress(v4Addr);
- if (withIPv4) {
- prop.addLinkAddress(
- new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address),
- NetworkConstants.IPV4_ADDR_BITS));
+ if (v6Addr != null) prop.addLinkAddress(v6Addr);
+
+ return new UpstreamNetworkState(prop, cap, network);
+ }
+
+ private NetworkCapabilities makeNetworkCapabilities(final int transportType) {
+ final NetworkCapabilities cap = new NetworkCapabilities();
+ cap.addTransportType(transportType);
+ if (transportType == TRANSPORT_VPN) {
+ cap.removeCapability(NET_CAPABILITY_NOT_VPN);
}
- if (withIPv6) {
- prop.addLinkAddress(
- new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"),
- NetworkConstants.RFC7421_PREFIX_LENGTH));
- }
- return prop;
+ return cap;
}
@Test
@@ -220,53 +213,76 @@
final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
// Force always get subAddress "43.5" for conflict testing.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
- // 1. Enable hotspot with prefix 192.168.43.0/24
+ // - Enable hotspot with prefix 192.168.43.0/24
final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
mHotspotIpServer);
final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr);
assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr);
- // 2. Update v6 only mobile network, hotspot prefix should not be removed.
- List<String> testConflicts;
- final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp);
+ // - test mobile network with null NetworkCapabilities. Ideally this should not happen,
+ // just make sure no crash in this case.
+ final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), null, null);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - test mobile upstream with no address.
+ final UpstreamNetworkState noAddress = buildUpstreamNetworkState(mMobileNetwork,
+ null, null, makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - Update v6 only mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v6OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+ null, new LinkAddress("2001:db8::/64"),
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyMobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork);
- // 3. Update v4 only mobile network, hotspot prefix should not be removed.
- final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp);
+ // - Update v4 only mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v4OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), null,
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyMobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 4. Update v4v6 mobile network, hotspot prefix should not be removed.
- final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp);
+ // - Update v4v6 mobile network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v4v6Mobile = buildUpstreamNetworkState(mMobileNetwork,
+ new LinkAddress("10.0.0.8/24"), new LinkAddress("2001:db8::/64"),
+ makeNetworkCapabilities(TRANSPORT_CELLULAR));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4v6Mobile);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 5. Update v6 only wifi network, hotspot prefix should not be removed.
- final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp);
+ // - Update v6 only wifi network, hotspot prefix should not be removed.
+ final UpstreamNetworkState v6OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+ null, new LinkAddress("2001:db8::/64"), makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
- // 6. Update v4 only wifi network, it conflict with hotspot prefix.
- final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+ // - Update vpn network, it conflict with hotspot prefix but VPN networks are ignored.
+ final UpstreamNetworkState v4OnlyVpn = buildUpstreamNetworkState(mVpnNetwork,
+ new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_VPN));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyVpn);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ // - Update v4 only wifi network, it conflict with hotspot prefix.
+ final UpstreamNetworkState v4OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
reset(mHotspotIpServer);
- // 7. Restart hotspot again and its prefix is different previous.
+ // - Restart hotspot again and its prefix is different previous.
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress(
mHotspotIpServer);
final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2);
assertNotEquals(hotspotPrefix, hotspotPrefix2);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2);
- mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+ mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- // 7. Usb tethering can be enabled and its prefix is different with conflict one.
+ // - Usb tethering can be enabled and its prefix is different with conflict one.
final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
mUsbIpServer);
final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr);
assertNotEquals(predefinedPrefix, usbPrefix);
assertNotEquals(hotspotPrefix2, usbPrefix);
when(mUsbIpServer.getAddress()).thenReturn(usbAddr);
- // 8. Disable wifi upstream, then wifi's prefix can be selected again.
+ // - Disable wifi upstream, then wifi's prefix can be selected again.
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
mEthernetIpServer);
diff --git a/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml b/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml
index 6842dde..d719a97 100644
--- a/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml
+++ b/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml
@@ -21,7 +21,6 @@
android:versionName="1.0">
<overlay
android:targetPackage="android"
- android:targetName="IconShapeCustomization"
android:category="android.theme.customization.adaptive_icon_shape"
android:priority="1"/>
diff --git a/packages/services/PacProcessor/Android.bp b/packages/services/PacProcessor/Android.bp
index 494a818..1fd972c 100644
--- a/packages/services/PacProcessor/Android.bp
+++ b/packages/services/PacProcessor/Android.bp
@@ -19,7 +19,6 @@
srcs: ["src/**/*.java"],
platform_apis: true,
certificate: "platform",
- jni_libs: ["libjni_pacprocessor"],
}
filegroup {
diff --git a/packages/services/PacProcessor/jni/Android.bp b/packages/services/PacProcessor/jni/Android.bp
deleted file mode 100644
index 0e7e101..0000000
--- a/packages/services/PacProcessor/jni/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_library_shared {
- name: "libjni_pacprocessor",
-
- srcs: [
- "jni_init.cpp",
- "com_android_pacprocessor_PacNative.cpp",
- ],
-
- shared_libs: [
- "libandroidfw",
- "libandroid_runtime",
- "liblog",
- "libutils",
- "libnativehelper",
- "libpac",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
- sanitize: {
- cfi: true,
- },
-}
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
deleted file mode 100644
index d969c69..0000000
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "PacProcessor"
-
-#include <stdlib.h>
-#include <string>
-
-#include <utils/Log.h>
-#include <utils/Mutex.h>
-#include "android_runtime/AndroidRuntime.h"
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-#include "proxy_resolver_v8_wrapper.h"
-
-namespace android {
-
-ProxyResolverV8Handle* proxyResolver = NULL;
-bool pacSet = false;
-
-std::u16string jstringToString16(JNIEnv* env, jstring jstr) {
- const jchar* str = env->GetStringCritical(jstr, 0);
- std::u16string str16(reinterpret_cast<const char16_t*>(str),
- env->GetStringLength(jstr));
- env->ReleaseStringCritical(jstr, str);
- return str16;
-}
-
-jstring string16ToJstring(JNIEnv* env, std::u16string string) {
- const char16_t* str = string.data();
- size_t len = string.length();
-
- return env->NewString(reinterpret_cast<const jchar*>(str), len);
-}
-
-static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
- jobject) {
- if (proxyResolver == NULL) {
- proxyResolver = ProxyResolverV8Handle_new();
- pacSet = false;
- return JNI_FALSE;
- }
- return JNI_TRUE;
-}
-
-static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
- jobject) {
- if (proxyResolver != NULL) {
- ProxyResolverV8Handle_delete(proxyResolver);
- proxyResolver = NULL;
- return JNI_FALSE;
- }
- return JNI_TRUE;
-}
-
-static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject,
- jstring script) {
- std::u16string script16 = jstringToString16(env, script);
-
- if (proxyResolver == NULL) {
- ALOGE("V8 Parser not started when setting PAC script");
- return JNI_TRUE;
- }
-
- if (ProxyResolverV8Handle_SetPacScript(proxyResolver, script16.data()) != OK) {
- ALOGE("Unable to set PAC script");
- return JNI_TRUE;
- }
- pacSet = true;
-
- return JNI_FALSE;
-}
-
-static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject,
- jstring url, jstring host) {
- std::u16string url16 = jstringToString16(env, url);
- std::u16string host16 = jstringToString16(env, host);
-
- if (proxyResolver == NULL) {
- ALOGE("V8 Parser not initialized when running PAC script");
- return NULL;
- }
-
- if (!pacSet) {
- ALOGW("Attempting to run PAC with no script set");
- return NULL;
- }
-
- std::unique_ptr<char16_t, decltype(&free)> result = std::unique_ptr<char16_t, decltype(&free)>(
- ProxyResolverV8Handle_GetProxyForURL(proxyResolver, url16.data(), host16.data()), &free);
- if (result.get() == NULL) {
- ALOGE("Error Running PAC");
- return NULL;
- }
-
- std::u16string ret(result.get());
- jstring jret = string16ToJstring(env, ret);
-
- return jret;
-}
-
-static const JNINativeMethod gMethods[] = {
- { "createV8ParserNativeLocked", "()Z",
- (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked},
- { "destroyV8ParserNativeLocked", "()Z",
- (void*)com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked},
- { "setProxyScriptNativeLocked", "(Ljava/lang/String;)Z",
- (void*)com_android_pacprocessor_PacNative_setProxyScriptNativeLocked},
- { "makeProxyRequestNativeLocked", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
- (void*)com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked},
-};
-
-int register_com_android_pacprocessor_PacNative(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/pacprocessor/PacNative",
- gMethods, NELEM(gMethods));
-}
-
-} /* namespace android */
diff --git a/packages/services/PacProcessor/jni/jni_init.cpp b/packages/services/PacProcessor/jni/jni_init.cpp
deleted file mode 100644
index de844c8..0000000
--- a/packages/services/PacProcessor/jni/jni_init.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "PacProcessor"
-
-#include <utils/Log.h>
-#include "jni.h"
-
-namespace android {
- extern int register_com_android_pacprocessor_PacNative(JNIEnv *env);
-}
-
-using namespace android;
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
- JNIEnv *env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed");
- return -1;
- }
-
- register_com_android_pacprocessor_PacNative(env);
-
- return JNI_VERSION_1_6;
-}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/LibpacInterface.java b/packages/services/PacProcessor/src/com/android/pacprocessor/LibpacInterface.java
deleted file mode 100644
index 103ef781..0000000
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/LibpacInterface.java
+++ /dev/null
@@ -1,34 +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 com.android.pacprocessor;
-
-/**
- * Common interface for both Android's and WebView's implementation of PAC processor.
- *
- * @hide
- */
-interface LibpacInterface {
- default boolean startPacSupport() {
- return true;
- }
-
- default boolean stopPacSupport() {
- return true;
- }
-
- boolean setCurrentProxyScript(String script);
- String makeProxyRequest(String url, String host);
-}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java
deleted file mode 100644
index 9c0cfc2..0000000
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Copyright (c) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.pacprocessor;
-
-import android.util.Log;
-
-/**
- * @hide
- */
-public class PacNative implements LibpacInterface {
- private static final String TAG = "PacProxy";
-
- private static final PacNative sInstance = new PacNative();
-
- private String mCurrentPac;
-
- private boolean mIsActive;
-
- // Only make native calls from inside synchronized blocks.
- private native boolean createV8ParserNativeLocked();
- private native boolean destroyV8ParserNativeLocked();
-
- private native boolean setProxyScriptNativeLocked(String script);
-
- private native String makeProxyRequestNativeLocked(String url, String host);
-
- static {
- System.loadLibrary("jni_pacprocessor");
- }
-
- private PacNative() {
-
- }
-
- public static PacNative getInstance() {
- return sInstance;
- }
-
- @Override
- public synchronized boolean startPacSupport() {
- if (createV8ParserNativeLocked()) {
- Log.e(TAG, "Unable to Create v8 Proxy Parser.");
- return false;
- }
- mIsActive = true;
- return true;
- }
-
- @Override
- public synchronized boolean stopPacSupport() {
- if (mIsActive) {
- if (destroyV8ParserNativeLocked()) {
- Log.e(TAG, "Unable to Destroy v8 Proxy Parser.");
- return false;
- }
- mIsActive = false;
- }
- return true;
- }
-
- @Override
- public synchronized boolean setCurrentProxyScript(String script) {
- if (setProxyScriptNativeLocked(script)) {
- Log.e(TAG, "Unable to parse proxy script.");
- return false;
- }
- return true;
- }
-
- @Override
- public synchronized String makeProxyRequest(String url, String host) {
- String ret = makeProxyRequestNativeLocked(url, host);
- if ((ret == null) || (ret.length() == 0)) {
- Log.e(TAG, "v8 Proxy request failed.");
- ret = null;
- }
- return ret;
- }
-
- public synchronized boolean isActive() {
- return mIsActive;
- }
-}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index 5a7de9f..46bda06 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -17,13 +17,14 @@
import android.app.Service;
import android.content.Intent;
-import android.content.res.Resources;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
+import android.webkit.PacProcessor;
+import com.android.internal.annotations.GuardedBy;
import com.android.net.IProxyService;
import java.net.MalformedURLException;
@@ -31,24 +32,21 @@
public class PacService extends Service {
private static final String TAG = "PacService";
- private static final boolean sUseWebViewPacProcessor = Resources.getSystem().getBoolean(
- com.android.internal.R.bool.config_useWebViewPacProcessor);
- private final LibpacInterface mLibpac = sUseWebViewPacProcessor
- ? PacWebView.getInstance()
- : PacNative.getInstance();
+ private Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final PacProcessor mPacProcessor = PacProcessor.getInstance();
private ProxyServiceStub mStub = new ProxyServiceStub();
@Override
public void onCreate() {
super.onCreate();
- mLibpac.startPacSupport();
}
@Override
public void onDestroy() {
- mLibpac.stopPacSupport();
super.onDestroy();
}
@@ -74,7 +72,10 @@
throw new IllegalArgumentException("Invalid host was passed");
}
}
- return mLibpac.makeProxyRequest(url, host);
+
+ synchronized (mLock) {
+ return mPacProcessor.findProxyForUrl(url);
+ }
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid URL was passed");
}
@@ -86,7 +87,11 @@
Log.e(TAG, "Only system user is allowed to call setPacFile");
throw new SecurityException();
}
- mLibpac.setCurrentProxyScript(script);
+ synchronized (mLock) {
+ if (!mPacProcessor.setProxyScript(script)) {
+ Log.e(TAG, "Unable to parse proxy script.");
+ }
+ }
}
}
}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacWebView.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacWebView.java
deleted file mode 100644
index 4dd00f1..0000000
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacWebView.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.pacprocessor;
-
-import android.util.Log;
-import android.webkit.PacProcessor;
-
-/**
- * @hide
- */
-public class PacWebView implements LibpacInterface {
- private static final String TAG = "PacWebView";
-
- private static final PacWebView sInstance = new PacWebView();
- private PacProcessor mProcessor = PacProcessor.getInstance();
-
- public static PacWebView getInstance() {
- return sInstance;
- }
-
- @Override
- public synchronized boolean setCurrentProxyScript(String script) {
- if (!mProcessor.setProxyScript(script)) {
- Log.e(TAG, "Unable to parse proxy script.");
- return false;
- }
- return true;
- }
-
- @Override
- public synchronized String makeProxyRequest(String url, String host) {
- return mProcessor.findProxyForUrl(url);
- }
-}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 34d2b73..15bd4dc 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -252,6 +252,10 @@
// Package: android
NOTE_ID_WIFI_SIM_REQUIRED = 60;
+ // TODO: remove this notification after feature development is done
+ // Inform the user a foreground service is restricted from BG-launch.
+ NOTE_FOREGROUND_SERVICE_BG_LAUNCH = 61;
+
// Display the Android Debug Protocol status
// Package: android
NOTE_ADB_WIFI_ACTIVE = 62;
diff --git a/services/Android.bp b/services/Android.bp
index ef52c2a..25a0d7e 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -3,6 +3,12 @@
plugins: [
"error_prone_android_framework",
],
+ errorprone: {
+ javacflags: [
+ "-Xep:AndroidFrameworkCompatChange:ERROR",
+ "-Xep:AndroidFrameworkUid:ERROR",
+ ],
+ },
}
filegroup {
diff --git a/services/backup/java/com/android/server/backup/DataChangedJournal.java b/services/backup/java/com/android/server/backup/DataChangedJournal.java
index 0e7fc93..4eb1d9a 100644
--- a/services/backup/java/com/android/server/backup/DataChangedJournal.java
+++ b/services/backup/java/com/android/server/backup/DataChangedJournal.java
@@ -40,7 +40,7 @@
* <p>This information is persisted to the filesystem so that it is not lost in the event of a
* reboot.
*/
-public final class DataChangedJournal {
+public class DataChangedJournal {
private static final String TAG = "DataChangedJournal";
private static final String FILE_NAME_PREFIX = "journal";
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6ca99d1..40b1718 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -317,7 +317,7 @@
AndroidFuture<Association> future = new AndroidFuture<>();
service.startDiscovery(request, callingPackage, callback, future);
return future;
- }).whenComplete(uncheckExceptions((association, err) -> {
+ }).cancelTimeout().whenComplete(uncheckExceptions((association, err) -> {
if (err == null) {
addAssociation(association);
} else {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index da5d1c2..8a1baf2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -136,6 +136,8 @@
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
+import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.os.Binder;
@@ -193,8 +195,6 @@
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
-import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index d907505..4a1820a 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -25,6 +25,7 @@
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
+import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -41,7 +42,6 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import com.android.net.module.util.DnsSdTxtRecord;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6d77486..7775354 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -18,14 +18,10 @@
import static android.Manifest.permission.ACCESS_MTP;
import static android.Manifest.permission.INSTALL_PACKAGES;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
-import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
-import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -137,7 +133,6 @@
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.AppFuseMount;
@@ -153,7 +148,6 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
-import com.android.server.SystemService.TargetUser;
import com.android.server.pm.Installer;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
@@ -2523,19 +2517,6 @@
abortIdleMaint(null);
}
- private void remountUidExternalStorage(int uid, int mode) {
- if (uid == Process.SYSTEM_UID) {
- // No need to remount uid for system because it has all access anyways
- return;
- }
-
- try {
- mVold.remountUid(uid, mode);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- }
- }
-
@Override
public void setDebugFlags(int flags, int mask) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
@@ -3847,21 +3828,6 @@
}
}
- private IAppOpsCallback.Stub mAppOpsCallback = new IAppOpsCallback.Stub() {
- @Override
- public void opChanged(int op, int uid, String packageName) throws RemoteException {
- if (!ENABLE_ISOLATED_STORAGE) return;
-
- int mountMode = getMountMode(uid, packageName);
- boolean isUidActive = LocalServices.getService(ActivityManagerInternal.class)
- .getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT;
-
- if (isUidActive) {
- remountUidExternalStorage(uid, mountMode);
- }
- }
- };
-
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
@@ -4236,19 +4202,9 @@
}
// Determine if caller is holding runtime permission
- final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
- uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
- // We're only willing to give out broad access if they also hold
- // runtime permission; this is a firm CDD requirement
- final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
- uid) == PERMISSION_GRANTED;
- if (hasFull && hasWrite) {
- return Zygote.MOUNT_EXTERNAL_FULL;
- }
-
// We're only willing to give out installer access if they also hold
// runtime permission; this is a firm CDD requirement
final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
@@ -4268,19 +4224,7 @@
if ((hasInstall || hasInstallOp) && hasWrite) {
return Zygote.MOUNT_EXTERNAL_INSTALLER;
}
-
- // Otherwise we're willing to give out sandboxed or non-sandboxed if
- // they hold the runtime permission
- boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
- uid, packageName) == MODE_ALLOWED;
-
- if (hasLegacy && hasWrite) {
- return Zygote.MOUNT_EXTERNAL_WRITE;
- } else if (hasLegacy && hasRead) {
- return Zygote.MOUNT_EXTERNAL_READ;
- } else {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
} catch (RemoteException e) {
// Should not happen
}
@@ -4570,12 +4514,6 @@
}
@Override
- public void onExternalStoragePolicyChanged(int uid, String packageName) {
- final int mountMode = getExternalStorageMountMode(uid, packageName);
- remountUidExternalStorage(uid, mountMode);
- }
-
- @Override
public int getExternalStorageMountMode(int uid, String packageName) {
if (ENABLE_ISOLATED_STORAGE) {
return getMountMode(uid, packageName);
@@ -4720,16 +4658,6 @@
updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
return;
}
-
- if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE
- || code == OP_WRITE_EXTERNAL_STORAGE
- || code == OP_REQUEST_INSTALL_PACKAGES)) {
- final UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- if (userManagerInternal.isUserInitialized(UserHandle.getUserId(uid))) {
- onExternalStoragePolicyChanged(uid, packageName);
- }
- }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 91a3fb0..b2e021f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -25,6 +25,7 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
+import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
@@ -119,6 +120,7 @@
import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -228,6 +230,10 @@
// white listed packageName.
ArraySet<String> mWhiteListAllowWhileInUsePermissionInFgs = new ArraySet<>();
+ // TODO: remove this after feature development is done
+ private static final SimpleDateFormat DATE_FORMATTER =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -553,8 +559,9 @@
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
&& mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
Slog.w(TAG, "startForegroundService() not allowed due to "
- + " mAllowStartForeground false: service "
+ + "mAllowStartForeground false: service "
+ r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
forcedStandby = true;
}
}
@@ -1459,6 +1466,7 @@
"Service.startForeground() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
updateServiceForegroundLocked(r.app, true);
ignoreForeground = true;
}
@@ -5056,4 +5064,27 @@
&& code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
}
+ // TODO: remove this notification after feature development is done
+ private void showFgsBgRestrictedNotificationLocked(ServiceRecord r) {
+ final Context context = mAm.mContext;
+ final String title = "Foreground Service BG-Launch Restricted";
+ final String content = "App restricted: " + r.mRecentCallingPackage;
+ final long now = System.currentTimeMillis();
+ final String bigText = DATE_FORMATTER.format(now) + " " + r.mInfoAllowStartForeground;
+ final String groupKey = "com.android.fgs-bg-restricted";
+ final Notification.Builder n =
+ new Notification.Builder(context,
+ SystemNotificationChannels.ALERTS)
+ .setGroup(groupKey)
+ .setSmallIcon(R.drawable.stat_sys_vitals)
+ .setWhen(0)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setStyle(new Notification.BigTextStyle().bigText(bigText));
+ context.getSystemService(NotificationManager.class).notifyAsUser(Long.toString(now),
+ NOTE_FOREGROUND_SERVICE_BG_LAUNCH, n.build(), UserHandle.ALL);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ffdcd15..d3f4667 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -153,7 +153,6 @@
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IApplicationThread;
-import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
import android.app.IProcessObserver;
@@ -286,7 +285,6 @@
import android.util.proto.ProtoUtils;
import android.view.Display;
import android.view.Gravity;
-import android.view.IRecentsAnimationRunner;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@@ -2840,18 +2838,6 @@
return mActivityTaskManager.startActivityFromRecents(taskId, bOptions);
}
- @Override
- public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
- IRecentsAnimationRunner recentsAnimationRunner) {
- mActivityTaskManager.startRecentsActivity(
- intent, assistDataReceiver, recentsAnimationRunner);
- }
-
- @Override
- public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
- mActivityTaskManager.cancelRecentsAnimation(restoreHomeStackPosition);
- }
-
/**
* This is the internal entry point for handling Activity.finish().
*
@@ -16492,7 +16478,7 @@
@Override
public int getStorageMountMode(int pid, int uid) {
if (uid == SHELL_UID || uid == ROOT_UID) {
- return Zygote.MOUNT_EXTERNAL_FULL;
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
synchronized (mPidsSelfLocked) {
final ProcessRecord pr = mPidsSelfLocked.get(pid);
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 692b3f1..b6010d9 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -33,7 +33,6 @@
import android.telephony.TelephonyManager;
import android.util.IntArray;
import android.util.Slog;
-import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BatteryStatsImpl;
@@ -607,49 +606,11 @@
}
wasReset = true;
} else {
- final long totalActiveTimeMs = txTimeMs + rxTimeMs;
- long maxExpectedIdleTimeMs;
- if (totalActiveTimeMs > timePeriodMs) {
- // Cap the max idle time at zero since the active time consumed the whole time
- maxExpectedIdleTimeMs = 0;
- if (totalActiveTimeMs > timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
- StringBuilder sb = new StringBuilder();
- sb.append("Total Active time ");
- TimeUtils.formatDuration(totalActiveTimeMs, sb);
- sb.append(" is longer than sample period ");
- TimeUtils.formatDuration(timePeriodMs, sb);
- sb.append(".\n");
- sb.append("Previous WiFi snapshot: ").append("idle=");
- TimeUtils.formatDuration(lastIdleMs, sb);
- sb.append(" rx=");
- TimeUtils.formatDuration(lastRxMs, sb);
- sb.append(" tx=");
- TimeUtils.formatDuration(lastTxMs, sb);
- sb.append(" e=").append(lastEnergy);
- sb.append("\n");
- sb.append("Current WiFi snapshot: ").append("idle=");
- TimeUtils.formatDuration(latest.getControllerIdleDurationMillis(), sb);
- sb.append(" rx=");
- TimeUtils.formatDuration(latest.getControllerRxDurationMillis(), sb);
- sb.append(" tx=");
- TimeUtils.formatDuration(latest.getControllerTxDurationMillis(), sb);
- sb.append(" e=").append(latest.getControllerEnergyUsedMicroJoules());
- Slog.wtf(TAG, sb.toString());
- }
- } else {
- maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
- }
// These times seem to be the most reliable.
deltaControllerTxDurationMillis = txTimeMs;
deltaControllerRxDurationMillis = rxTimeMs;
deltaControllerScanDurationMillis = scanTimeMs;
- // WiFi calculates the idle time as a difference from the on time and the various
- // Rx + Tx times. There seems to be some missing time there because this sometimes
- // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
- // time from the difference in timestamps.
- // b/21613534
- deltaControllerIdleDurationMillis =
- Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
+ deltaControllerIdleDurationMillis = idleTimeMs;
deltaControllerEnergyUsedMicroJoules =
Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy);
wasReset = false;
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 4192455..529c651 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.app.ActivityThread;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
@@ -94,6 +95,8 @@
sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST, String.class);
sGlobalSettingToTypeMap.put(
+ Settings.Global.ANGLE_EGL_FEATURES, String.class);
+ sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
@@ -221,16 +224,17 @@
@VisibleForTesting
void populateSettings(Bundle snapshot, Map<String, Class<?>> map) {
- Context context = mActivityManagerService.mContext;
+ final Context context = mActivityManagerService.mContext;
+ final ContentResolver cr = context.getContentResolver();
for (Map.Entry<String, Class<?>> entry : map.entrySet()) {
String setting = entry.getKey();
final String value;
if (map == sSecureSettingToTypeMap) {
- value = Settings.Secure.getString(context.getContentResolver(), setting);
+ value = Settings.Secure.getStringForUser(cr, setting, cr.getUserId());
} else if (map == sSystemSettingToTypeMap) {
- value = Settings.System.getString(context.getContentResolver(), setting);
+ value = Settings.System.getStringForUser(cr, setting, cr.getUserId());
} else {
- value = Settings.Global.getString(context.getContentResolver(), setting);
+ value = Settings.Global.getString(cr, setting);
}
if (value == null) {
snapshot.remove(setting);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5e65563..ed47616d9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -92,7 +92,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.system.Os;
import android.text.TextUtils;
@@ -1780,14 +1779,10 @@
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DIRECT_BOOT_AUTO, app.userId);
- if (StorageManager.hasIsolatedStorage() && mountExtStorageFull) {
- mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
- } else {
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
- app.info.packageName);
- }
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
+ app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -1918,7 +1913,9 @@
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
- instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
+ // If ABI override is specified, use the isa derived from the value of ABI override.
+ // Otherwise, use the isa derived from primary ABI
+ instructionSet = VMRuntime.getInstructionSet(requiredAbi);
}
app.gids = gids;
@@ -1927,7 +1924,7 @@
// If instructionSet is non-null, this indicates that the system_server is spawning a
// process with an ISA that may be different from its own. System (kernel and hardware)
- // compatililty for these features is checked in the decideTaggingLevel in the
+ // compatibility for these features is checked in the decideTaggingLevel in the
// system_server process (not the child process). As both MTE and TBI are only supported
// in aarch64, we can simply ensure that the new process is also aarch64. This prevents
// the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index eb60573..6c08826 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -712,8 +712,6 @@
Slog.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
// Pre-created user was started right after creation so services could properly
// intialize it; it should be stopped right away as it's not really a "real" user.
- // TODO(b/143092698): in the long-term, it might be better to add a onCreateUser()
- // callback on SystemService instead.
stopUser(userInfo.id, /* force= */ true, /* allowDelayedLocking= */ false,
/* stopUserCallback= */ null, /* keyEvictedCallback= */ null);
return;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 668713f..7dbb39e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -584,29 +584,6 @@
// process is not in foreground.
return MODE_IGNORED;
}
- } else if (mode == MODE_ALLOWED) {
- switch (op) {
- case OP_CAMERA:
- if (mActivityManagerInternal != null
- && mActivityManagerInternal.isPendingTopUid(uid)) {
- return MODE_ALLOWED;
- } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
- return MODE_ALLOWED;
- } else {
- return MODE_IGNORED;
- }
- case OP_RECORD_AUDIO:
- if (mActivityManagerInternal != null
- && mActivityManagerInternal.isPendingTopUid(uid)) {
- return MODE_ALLOWED;
- } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
- return MODE_ALLOWED;
- } else {
- return MODE_IGNORED;
- }
- default:
- return MODE_ALLOWED;
- }
}
return mode;
}
@@ -1732,24 +1709,13 @@
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
- packageName, null, true, "External storage policy", true)
- != AppOpsManager.MODE_ALLOWED) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- }
- if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
- packageName, null, true, "External storage policy", true)
- != AppOpsManager.MODE_ALLOWED) {
- return Zygote.MOUNT_EXTERNAL_READ;
- }
- return Zygote.MOUNT_EXTERNAL_WRITE;
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
@Override
public boolean hasExternalStorage(int uid, String packageName) {
final int mountMode = getMountMode(uid, packageName);
- return mountMode == Zygote.MOUNT_EXTERNAL_READ
- || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+ return mountMode != Zygote.MOUNT_EXTERNAL_NONE;
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index c300169..88804e2 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -49,8 +49,10 @@
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
+import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.Binder;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -448,7 +450,7 @@
/**
* Converts from {@link BiometricManager.Authenticators} biometric strength to the internal
- * {@link SensorProperties} strength.
+ * {@link SensorPropertiesInternal} strength.
*/
public static @SensorProperties.Strength int authenticatorStrengthToPropertyStrength(
@BiometricManager.Authenticators.Types int strength) {
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 4be596d..ff410fc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -18,19 +18,26 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
+import android.util.EventLog;
import android.util.Slog;
+import com.android.server.biometrics.Utils;
+
import java.util.ArrayList;
+import java.util.List;
/**
* A class to keep track of the authentication state for a given client.
@@ -136,7 +143,54 @@
pm.incrementAuthForUser(getTargetUserId(), authenticated);
}
+ // Ensure authentication only succeeds if the client activity is on top or is keyguard.
+ boolean isBackgroundAuth = false;
+ if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
+ try {
+ final List<ActivityManager.RunningTaskInfo> tasks =
+ mActivityTaskManager.getTasks(1);
+ if (tasks == null || tasks.isEmpty()) {
+ Slog.e(TAG, "No running tasks reported");
+ isBackgroundAuth = true;
+ } else {
+ final ComponentName topActivity = tasks.get(0).topActivity;
+ if (topActivity == null) {
+ Slog.e(TAG, "Unable to get top activity");
+ isBackgroundAuth = true;
+ } else {
+ final String topPackage = topActivity.getPackageName();
+ if (!topPackage.contentEquals(getOwnerString())) {
+ Slog.e(TAG, "Background authentication detected, top: " + topPackage
+ + ", client: " + this);
+ isBackgroundAuth = true;
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get running tasks", e);
+ isBackgroundAuth = true;
+ }
+ }
+
+ // Fail authentication if we can't confirm the client activity is on top.
+ if (isBackgroundAuth) {
+ Slog.e(TAG, "Failing possible background authentication");
+ authenticated = false;
+
+ // SafetyNet logging for exploitation attempts of b/159249069.
+ final ApplicationInfo appInfo = getContext().getApplicationInfo();
+ EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
+ "Attempted background authentication");
+ }
+
if (authenticated) {
+ // SafetyNet logging for b/159249069 if constraint is violated.
+ if (isBackgroundAuth) {
+ final ApplicationInfo appInfo = getContext().getApplicationInfo();
+ EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
+ "Successful background authentication!");
+ }
+
mAlreadyDone = true;
if (listener != null) {
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 588e865..ce2d340 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -28,6 +28,7 @@
import android.os.ServiceManager;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.io.PrintWriter;
@@ -37,9 +38,9 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Date;
+import java.util.Deque;
import java.util.List;
import java.util.Locale;
-import java.util.Queue;
/**
* A scheduler for biometric HAL operations. Maintains a queue of {@link ClientMonitor} operations,
@@ -53,7 +54,8 @@
/**
* Contains all the necessary information for a HAL operation.
*/
- private static final class Operation {
+ @VisibleForTesting
+ static final class Operation {
/**
* The operation is added to the list of pending operations and waiting for its turn.
@@ -176,8 +178,8 @@
@NonNull private final IBiometricService mBiometricService;
@NonNull private final Handler mHandler = new Handler(Looper.getMainLooper());
@NonNull private final InternalCallback mInternalCallback;
- @NonNull private final Queue<Operation> mPendingOperations;
- @Nullable private Operation mCurrentOperation;
+ @VisibleForTesting @NonNull final Deque<Operation> mPendingOperations;
+ @VisibleForTesting @Nullable Operation mCurrentOperation;
@NonNull private final ArrayDeque<CrashState> mCrashStates;
// Internal callback, notified when an operation is complete. Notifies the requester
@@ -226,6 +228,18 @@
}
}
+ @VisibleForTesting
+ BiometricScheduler(@NonNull String tag,
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull IBiometricService biometricService) {
+ mBiometricTag = tag;
+ mInternalCallback = new InternalCallback();
+ mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
+ mPendingOperations = new ArrayDeque<>();
+ mBiometricService = biometricService;
+ mCrashStates = new ArrayDeque<>();
+ }
+
/**
* Creates a new scheduler.
* @param tag for the specific instance of the scheduler. Should be unique.
@@ -234,13 +248,8 @@
*/
public BiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- mBiometricTag = tag;
- mInternalCallback = new InternalCallback();
- mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
- mPendingOperations = new ArrayDeque<>();
- mBiometricService = IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE));
- mCrashStates = new ArrayDeque<>();
+ this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE)));
}
/**
@@ -295,9 +304,50 @@
// to arrive at the head of the queue, before pinging it to start.
final boolean shouldStartNow = currentClient.getCookie() == 0;
if (shouldStartNow) {
- Slog.d(getTag(), "[Starting] " + mCurrentOperation);
- currentClient.start(getInternalCallback());
- mCurrentOperation.state = Operation.STATE_STARTED;
+ if (mCurrentOperation.clientMonitor.getFreshDaemon() == null) {
+ // Note down current length of queue
+ final int pendingOperationsLength = mPendingOperations.size();
+ final Operation lastOperation = mPendingOperations.peekLast();
+ Slog.e(getTag(), "[Unable To Start] " + mCurrentOperation
+ + ". Last pending operation: " + lastOperation);
+
+ // For current operations, 1) unableToStart, which notifies the caller-side, then
+ // 2) notify operation's callback, to notify applicable system service that the
+ // operation failed.
+ mCurrentOperation.clientMonitor.unableToStart();
+ if (mCurrentOperation.mClientCallback != null) {
+ mCurrentOperation.mClientCallback
+ .onClientFinished(mCurrentOperation.clientMonitor, false /* success */);
+ }
+
+ // Then for each operation currently in the pending queue at the time of this
+ // failure, do the same as above. Otherwise, it's possible that something like
+ // setActiveUser fails, but then authenticate (for the wrong user) is invoked.
+ for (int i = 0; i < pendingOperationsLength; i++) {
+ final Operation operation = mPendingOperations.pollFirst();
+ if (operation == null) {
+ Slog.e(getTag(), "Null operation, index: " + i
+ + ", expected length: " + pendingOperationsLength);
+ break;
+ }
+ operation.clientMonitor.unableToStart();
+ if (operation.mClientCallback != null) {
+ operation.mClientCallback.onClientFinished(operation.clientMonitor,
+ false /* success */);
+ }
+ Slog.w(getTag(), "[Aborted Operation] " + operation);
+ }
+
+ // It's possible that during cleanup a new set of operations came in. We can try to
+ // run these. A single request from the manager layer to the service layer may
+ // actually be multiple operations (i.e. updateActiveUser + authenticate).
+ mCurrentOperation = null;
+ startNextOperationIfIdle();
+ } else {
+ Slog.d(getTag(), "[Starting] " + mCurrentOperation);
+ currentClient.start(getInternalCallback());
+ mCurrentOperation.state = Operation.STATE_STARTED;
+ }
} else {
try {
mBiometricService.onReadyForAuthentication(currentClient.getCookie());
@@ -338,9 +388,21 @@
return;
}
- Slog.d(getTag(), "[Starting] Prepared client: " + mCurrentOperation);
- mCurrentOperation.state = Operation.STATE_STARTED;
- mCurrentOperation.clientMonitor.start(getInternalCallback());
+ if (mCurrentOperation.clientMonitor.getFreshDaemon() == null) {
+ Slog.e(getTag(), "[Unable To Start] Prepared client: " + mCurrentOperation);
+ // This is BiometricPrompt trying to auth but something's wrong with the HAL.
+ mCurrentOperation.clientMonitor.unableToStart();
+ if (mCurrentOperation.mClientCallback != null) {
+ mCurrentOperation.mClientCallback.onClientFinished(mCurrentOperation.clientMonitor,
+ false /* success */);
+ }
+ mCurrentOperation = null;
+ startNextOperationIfIdle();
+ } else {
+ Slog.d(getTag(), "[Starting] Prepared client: " + mCurrentOperation);
+ mCurrentOperation.state = Operation.STATE_STARTED;
+ mCurrentOperation.clientMonitor.start(getInternalCallback());
+ }
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 92c498c..bac944f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -27,8 +27,6 @@
private static final String TAG = "GenerateChallengeClient";
- protected long mChallenge;
-
public GenerateChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String owner, int sensorId) {
@@ -51,12 +49,5 @@
super.start(callback);
startHalOperation();
- try {
- getListener().onChallengeGenerated(getSensorId(), mChallenge);
- mCallback.onClientFinished(this, true /* success */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- mCallback.onClientFinished(this, false /* success */);
- }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
index c17bc91..c2d4c15 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
@@ -31,7 +31,7 @@
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
-import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.Build;
@@ -48,6 +48,7 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AcquisitionClient;
@@ -87,7 +88,7 @@
static final String NOTIFICATION_TAG = "FaceService";
static final int NOTIFICATION_ID = 1;
- @NonNull private final FaceSensorProperties mFaceSensorProperties;
+ @NonNull private final FaceSensorPropertiesInternal mFaceSensorProperties;
@NonNull private final Context mContext;
@NonNull private final BiometricScheduler mScheduler;
@NonNull private final Handler mHandler;
@@ -278,15 +279,14 @@
}
};
+ @VisibleForTesting
Face10(@NonNull Context context, int sensorId,
@BiometricManager.Authenticators.Types int strength,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
- final boolean supportsSelfIllumination = context.getResources()
- .getBoolean(R.bool.config_faceAuthSupportsSelfIllumination);
- final int maxTemplatesAllowed = context.getResources()
- .getInteger(R.integer.config_faceMaxTemplatesPerUser);
- mFaceSensorProperties = new FaceSensorProperties(sensorId, false /* supportsFaceDetect */,
- supportsSelfIllumination, maxTemplatesAllowed);
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ boolean supportsSelfIllumination, int maxTemplatesAllowed) {
+ mFaceSensorProperties = new FaceSensorPropertiesInternal(sensorId,
+ Utils.authenticatorStrengthToPropertyStrength(strength),
+ maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination);
mContext = context;
mSensorId = sensorId;
mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
@@ -305,6 +305,14 @@
}
}
+ Face10(@NonNull Context context, int sensorId,
+ @BiometricManager.Authenticators.Types int strength,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ this(context, sensorId, strength, lockoutResetDispatcher,
+ context.getResources().getBoolean(R.bool.config_faceAuthSupportsSelfIllumination),
+ context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser));
+ }
+
@Override
public void serviceDied(long cookie) {
Slog.e(TAG, "HAL died");
@@ -511,19 +519,17 @@
@NonNull String opPackageName) {
mHandler.post(() -> {
if (mCurrentChallengeOwner != null) {
- Slog.w(TAG, "Current challenge owner: " + mCurrentChallengeOwner
- + ", interrupted by: " + opPackageName);
final ClientMonitorCallbackConverter listener =
mCurrentChallengeOwner.getListener();
- if (listener == null) {
- Slog.w(TAG, "Null listener, skip sending interruption callback");
- return;
- }
-
- try {
- listener.onChallengeInterrupted(mSensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to notify challenge interrupted", e);
+ Slog.w(TAG, "Current challenge owner: " + mCurrentChallengeOwner
+ + ", listener: " + listener
+ + ", interrupted by: " + opPackageName);
+ if (listener != null) {
+ try {
+ listener.onChallengeInterrupted(mSensorId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to notify challenge interrupted", e);
+ }
}
}
@@ -547,7 +553,8 @@
void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String owner) {
mHandler.post(() -> {
- if (!mCurrentChallengeOwner.getOwnerString().contentEquals(owner)) {
+ if (mCurrentChallengeOwner != null &&
+ !mCurrentChallengeOwner.getOwnerString().contentEquals(owner)) {
Slog.e(TAG, "scheduleRevokeChallenge, package: " + owner
+ " attempting to revoke challenge owned by: "
+ mCurrentChallengeOwner.getOwnerString());
@@ -566,6 +573,13 @@
return;
}
+ if (mCurrentChallengeOwner == null) {
+ // Can happen if revoke is incorrectly called, for example without a
+ // preceding generateChallenge
+ Slog.w(TAG, "Current challenge owner is null");
+ return;
+ }
+
final FaceGenerateChallengeClient previousChallengeOwner =
mCurrentChallengeOwner.getInterruptedClient();
mCurrentChallengeOwner = null;
@@ -672,7 +686,8 @@
return daemon != null;
}
- @NonNull FaceSensorProperties getFaceSensorProperties() {
+ @NonNull
+ FaceSensorPropertiesInternal getFaceSensorProperties() {
return mFaceSensorProperties;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
index ba401f2..406a7cc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
@@ -59,7 +59,14 @@
@Override
protected void startHalOperation() {
try {
- mChallenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+ final long challenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+ try {
+ getListener().onChallengeGenerated(getSensorId(), challenge);
+ mCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "generateChallenge failed", e);
}
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 82dc0d0..83f10c8 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
@@ -26,7 +26,7 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.Face;
-import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -67,9 +67,11 @@
*/
private final class FaceServiceWrapper extends IFaceService.Stub {
@Override // Binder call
- public List<FaceSensorProperties> getSensorProperties(String opPackageName) {
+ public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
+ String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final List<FaceSensorProperties> properties = new ArrayList<>();
+
+ final List<FaceSensorPropertiesInternal> properties = new ArrayList<>();
if (mFace10 != null) {
properties.add(mFace10.getFaceSensorProperties());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index cc94079..d353994 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,7 +33,7 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -87,9 +87,11 @@
*/
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
@Override // Binder call
- public List<FingerprintSensorProperties> getSensorProperties(String opPackageName) {
+ public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(
+ String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final List<FingerprintSensorProperties> properties =
+
+ final List<FingerprintSensorPropertiesInternal> properties =
FingerprintService.this.getSensorProperties();
Slog.d(TAG, "Retrieved sensor properties for: " + opPackageName
@@ -347,7 +349,8 @@
final long ident = Binder.clearCallingIdentity();
try {
for (ServiceProvider provider : mServiceProviders) {
- for (FingerprintSensorProperties props : provider.getSensorProperties()) {
+ for (FingerprintSensorPropertiesInternal props :
+ provider.getSensorProperties()) {
if (args.length > 0 && "--proto".equals(args[0])) {
provider.dumpProto(props.sensorId, fd);
} else {
@@ -566,7 +569,7 @@
*/
@Nullable
private Pair<Integer, ServiceProvider> getSingleProvider() {
- final List<FingerprintSensorProperties> properties = getSensorProperties();
+ final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties();
if (properties.size() != 1) {
return null;
}
@@ -585,8 +588,8 @@
}
@NonNull
- private List<FingerprintSensorProperties> getSensorProperties() {
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ private List<FingerprintSensorPropertiesInternal> getSensorProperties() {
+ final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>();
for (ServiceProvider provider : mServiceProviders) {
properties.addAll(provider.getSensorProperties());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 1fcc58c..d7338a0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
@@ -49,8 +49,8 @@
* }
*
* For operations that are supported by some providers but not others, clients are required
- * to check (e.g. via {@link FingerprintManager#getSensorProperties()}) to ensure that the code
- * path isn't taken. ServiceProviders will provide a no-op for unsupported operations to
+ * to check (e.g. via {@link FingerprintManager#getSensorPropertiesInternal()}) to ensure that the
+ * code path isn't taken. ServiceProviders will provide a no-op for unsupported operations to
* fail safely.
*/
@SuppressWarnings("deprecation")
@@ -60,7 +60,7 @@
*/
boolean containsSensor(int sensorId);
- @NonNull List<FingerprintSensorProperties> getSensorProperties();
+ @NonNull List<FingerprintSensorPropertiesInternal> getSensorProperties();
void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
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 30cbf40..f890f57 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
@@ -33,6 +33,7 @@
import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
@@ -91,7 +92,7 @@
final Context mContext;
private final IActivityTaskManager mActivityTaskManager;
- @NonNull private final FingerprintSensorProperties mSensorProperties;
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
private final Handler mHandler;
private final LockoutResetDispatcher mLockoutResetDispatcher;
@@ -347,7 +348,7 @@
final int maxEnrollmentsPerUser = mContext.getResources()
.getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
- mSensorProperties = new FingerprintSensorProperties(sensorId,
+ mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId,
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
sensorType, resetLockoutRequiresHardwareAuthToken);
}
@@ -487,8 +488,8 @@
@Override
@NonNull
- public List<FingerprintSensorProperties> getSensorProperties() {
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
+ final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>();
properties.add(mSensorProperties);
return properties;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index d68671b..5dda5a8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -26,6 +26,7 @@
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
import android.os.IBinder;
@@ -124,7 +125,7 @@
@NonNull private final TestableBiometricScheduler mScheduler;
@NonNull private final Handler mHandler;
- @NonNull private final FingerprintSensorProperties mSensorProperties;
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
@NonNull private final MockHalResultController mMockHalResultController;
@NonNull private final TrustManager mTrustManager;
@NonNull private final SparseBooleanArray mUserHasTrust;
@@ -418,7 +419,7 @@
final boolean resetLockoutRequiresHardwareAuthToken = false;
final int maxTemplatesAllowed = mContext.getResources()
.getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
- mSensorProperties = new FingerprintSensorProperties(sensorId,
+ mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId,
Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
resetLockoutRequiresHardwareAuthToken);
@@ -453,8 +454,8 @@
@Override
@NonNull
- public List<FingerprintSensorProperties> getSensorProperties() {
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
+ final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>();
properties.add(mSensorProperties);
return properties;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
index abaaac5..5169c7d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
@@ -45,7 +45,14 @@
@Override
protected void startHalOperation() {
try {
- mChallenge = getFreshDaemon().preEnroll();
+ final long challenge = getFreshDaemon().preEnroll();
+ try {
+ getListener().onChallengeGenerated(getSensorId(), challenge);
+ mCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "preEnroll failed", e);
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index fa03e59..62630300 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -60,12 +60,12 @@
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.util.IpRange;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.HexDump;
-import com.android.net.module.util.IpRange;
import java.net.Inet4Address;
import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index bb6f14c..96679c3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -16,6 +16,8 @@
package com.android.server.hdmi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.CecMessage;
import android.hardware.tv.cec.V1_0.HotplugEvent;
@@ -774,6 +776,7 @@
private IHdmiCec mHdmiCec;
private final Object mLock = new Object();
private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+ @Nullable private HdmiCecCallback mCallback;
@Override
public String nativeInit() {
@@ -782,7 +785,7 @@
boolean connectToHal() {
try {
- mHdmiCec = IHdmiCec.getService();
+ mHdmiCec = IHdmiCec.getService(true);
try {
mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
} catch (RemoteException e) {
@@ -796,7 +799,8 @@
}
@Override
- public void setCallback(HdmiCecCallback callback) {
+ public void setCallback(@NonNull HdmiCecCallback callback) {
+ mCallback = callback;
try {
mHdmiCec.setCallback(callback);
} catch (RemoteException e) {
@@ -936,6 +940,10 @@
if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting");
connectToHal();
+ // Reconnect the callback
+ if (mCallback != null) {
+ setCallback(mCallback);
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 68473c1..29bdd6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -379,7 +379,8 @@
assertRunOnServiceThread();
if (reason == mService.INITIATED_BY_ENABLE_CEC) {
mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
- getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+ getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST,
+ "HdmiCecLocalDeviceAudioSystem#onAddressAllocated()");
}
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
@@ -1324,7 +1325,8 @@
if (getRoutingPort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
mService.setAndBroadcastActiveSourceFromOneDeviceType(
- message.getSource(), mService.getPhysicalAddress());
+ message.getSource(), mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceAudioSystem#handleRoutingChangeAndInformationForSwitch()");
return;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 6e6d848..6257032 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
+import android.annotation.CallSuper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
@@ -96,7 +97,8 @@
assertRunOnServiceThread();
if (reason == mService.INITIATED_BY_ENABLE_CEC) {
mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
- getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+ getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST,
+ "HdmiCecLocalDevicePlayback#onAddressAllocated()");
}
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -165,7 +167,7 @@
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
mCecMessageCache.flushAll();
- // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+ // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
if (!connected) {
getWakeLock().release();
}
@@ -178,13 +180,12 @@
if (!mService.isControlEnabled()) {
return;
}
- if (mIsActiveSource) {
+ if (isActiveSource()) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
mAddress, mService.getPhysicalAddress()));
}
- boolean wasActiveSource = mIsActiveSource;
+ boolean wasActiveSource = isActiveSource();
// Invalidate the internal active source record when goes to standby
- // This set will also update mIsActiveSource
mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
"HdmiCecLocalDevicePlayback#onStandby()");
if (initiatedByCec || !mAutoTvOff || !wasActiveSource) {
@@ -229,12 +230,13 @@
}
@Override
+ @CallSuper
@ServiceThreadOnly
@VisibleForTesting
- void setIsActiveSource(boolean on) {
+ protected void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
assertRunOnServiceThread();
- super.setIsActiveSource(on);
- if (on) {
+ super.setActiveSource(logicalAddress, physicalAddress, caller);
+ if (isActiveSource()) {
getWakeLock().acquire();
} else {
getWakeLock().release();
@@ -291,7 +293,7 @@
@Override
protected void wakeUpIfActiveSource() {
- if (!mIsActiveSource) {
+ if (!isActiveSource()) {
return;
}
// Wake up the device if the power is in standby mode, or its screen is off -
@@ -399,9 +401,16 @@
"HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
return;
}
+ if (!isActiveSource()) {
+ // If routing is changed to the device while Active Source, don't invalidate the
+ // Active Source
+ setActiveSource(physicalAddress,
+ "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
+ }
switch (mPlaybackDeviceActionOnRoutingControl) {
case WAKE_UP_AND_SEND_ACTIVE_SOURCE:
- setAndBroadcastActiveSource(message, physicalAddress);
+ setAndBroadcastActiveSource(message, physicalAddress,
+ "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
break;
case WAKE_UP_ONLY:
mService.wakeUp();
@@ -436,7 +445,7 @@
@Override
protected void dump(final IndentingPrintWriter pw) {
super.dump(pw);
- pw.println("mIsActiveSource: " + mIsActiveSource);
+ pw.println("isActiveSource(): " + isActiveSource());
pw.println("mAutoTvOff:" + mAutoTvOff);
}
@@ -457,7 +466,7 @@
@Override
public void acquire() {
mWakeLock.acquire();
- HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
+ HdmiLogger.debug("active source: %b. Wake lock acquired", isActiveSource());
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 4ff36c4..4325f79 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
+import android.annotation.CallSuper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
@@ -36,10 +37,6 @@
private static final String TAG = "HdmiCecLocalDeviceSource";
- // Indicate if current device is Active Source or not
- @VisibleForTesting
- protected boolean mIsActiveSource = false;
-
// Device has cec switch functionality or not.
// Default is false.
protected boolean mIsSwitchDevice = HdmiProperties.is_switch().orElse(false);
@@ -78,7 +75,7 @@
if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
}
- // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+ // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
if (connected) {
mService.wakeUp();
}
@@ -118,10 +115,21 @@
// Nothing to do.
}
+ @Override
+ @CallSuper
+ @ServiceThreadOnly
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
+ boolean wasActiveSource = isActiveSource();
+ super.setActiveSource(logicalAddress, physicalAddress, caller);
+ if (wasActiveSource && !isActiveSource()) {
+ onActiveSourceLost();
+ }
+ }
+
@ServiceThreadOnly
protected void setActiveSource(int physicalAddress, String caller) {
assertRunOnServiceThread();
- // Invalidate the internal active source record. This will also update mIsActiveSource.
+ // Invalidate the internal active source record.
ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress);
setActiveSource(activeSource, caller);
}
@@ -135,7 +143,6 @@
if (!getActiveSource().equals(activeSource)) {
setActiveSource(activeSource, "HdmiCecLocalDeviceSource#handleActiveSource()");
}
- setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
if (isRoutingControlFeatureEnabled()) {
switchInputOnReceivingNewActivePath(physicalAddress);
@@ -159,9 +166,11 @@
// If current device is the target path, set to Active Source.
// If the path is under the current device, should switch
if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
- setAndBroadcastActiveSource(message, physicalAddress);
- }
- if (physicalAddress != mService.getPhysicalAddress()) {
+ setAndBroadcastActiveSource(message, physicalAddress,
+ "HdmiCecLocalDeviceSource#handleSetStreamPath()");
+ } else if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+ // Invalidate the active source if stream path is set to other physical address or
+ // our physical address while not active source
setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleSetStreamPath()");
}
switchInputOnReceivingNewActivePath(physicalAddress);
@@ -173,19 +182,15 @@
protected boolean handleRoutingChange(HdmiCecMessage message) {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
- if (physicalAddress != mService.getPhysicalAddress()) {
+ if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+ // Invalidate the active source if routing is changed to other physical address or
+ // our physical address while not active source
setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingChange()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
return true;
}
- // if the current device is a pure playback device
- if (!mIsSwitchDevice
- && physicalAddress == mService.getPhysicalAddress()
- && mService.isPlaybackDevice()) {
- setAndBroadcastActiveSource(message, physicalAddress);
- }
handleRoutingChangeAndInformation(physicalAddress, message);
return true;
}
@@ -195,19 +200,15 @@
protected boolean handleRoutingInformation(HdmiCecMessage message) {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
- if (physicalAddress != mService.getPhysicalAddress()) {
+ if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+ // Invalidate the active source if routing is changed to other physical address or
+ // our physical address while not active source
setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingInformation()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
return true;
}
- // if the current device is a pure playback device
- if (!mIsSwitchDevice
- && physicalAddress == mService.getPhysicalAddress()
- && mService.isPlaybackDevice()) {
- setAndBroadcastActiveSource(message, physicalAddress);
- }
handleRoutingChangeAndInformation(physicalAddress, message);
return true;
}
@@ -236,23 +237,21 @@
// since service can decide who will be the active source when the device supports
// multiple device types in this method.
// This method should only be called when the device can be the active source.
- protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
+ protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress,
+ String caller) {
mService.setAndBroadcastActiveSource(
- physicalAddress, getDeviceInfo().getDeviceType(), message.getSource());
+ physicalAddress, getDeviceInfo().getDeviceType(), message.getSource(), caller);
}
+ // Indicates if current device is the active source or not
@ServiceThreadOnly
- void setIsActiveSource(boolean on) {
- assertRunOnServiceThread();
- boolean wasActiveSource = mIsActiveSource;
- mIsActiveSource = on;
- if (wasActiveSource && !mIsActiveSource) {
- onActiveSourceLost();
- }
+ protected boolean isActiveSource() {
+ return getActiveSource().equals(getDeviceInfo().getLogicalAddress(),
+ getDeviceInfo().getPhysicalAddress());
}
protected void wakeUpIfActiveSource() {
- if (!mIsActiveSource) {
+ if (!isActiveSource()) {
return;
}
// Wake up the device
@@ -261,7 +260,7 @@
}
protected void maySendActiveSource(int dest) {
- if (!mIsActiveSource) {
+ if (!isActiveSource()) {
return;
}
addAndStartAction(new ActiveSourceAction(this, dest));
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b407234..a60a676 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1600,7 +1600,7 @@
if (isPlaybackDevice()) {
// if playback device itself is the active source,
// return its own device info.
- if (playback() != null && playback().mIsActiveSource) {
+ if (playback() != null && playback().isActiveSource()) {
return playback().getDeviceInfo();
}
// Otherwise get the active source and look for it from the device list
@@ -3242,20 +3242,12 @@
HdmiUtils.pathRelationship(getPhysicalAddress(), physicalAddress));
// If the current device is a source device, check if the current Active Source matches
- // the local device info. Set mIsActiveSource of the local device accordingly.
+ // the local device info.
for (HdmiCecLocalDevice device : getAllLocalDevices()) {
- // mIsActiveSource only exists in source device, ignore this setting if the current
- // device is not an HdmiCecLocalDeviceSource.
- if (!(device instanceof HdmiCecLocalDeviceSource)) {
- device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
- false, caller);
- continue;
- }
boolean deviceIsActiveSource =
logicalAddress == device.getDeviceInfo().getLogicalAddress()
&& physicalAddress == getPhysicalAddress();
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(deviceIsActiveSource);
device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
deviceIsActiveSource, caller);
}
@@ -3266,22 +3258,22 @@
// For example, when receiving broadcast messages, all the device types will call this
// method but only one of them will be the Active Source.
protected void setAndBroadcastActiveSource(
- int physicalAddress, int deviceType, int source) {
+ int physicalAddress, int deviceType, int source, String caller) {
// If the device has both playback and audio system logical addresses,
// playback will claim active source. Otherwise audio system will.
if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
HdmiCecLocalDevicePlayback playback = playback();
- playback.setIsActiveSource(true);
+ playback.setActiveSource(playback.getDeviceInfo().getLogicalAddress(), physicalAddress,
+ caller);
playback.wakeUpIfActiveSource();
playback.maySendActiveSource(source);
}
if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
- if (playback() != null) {
- audioSystem.setIsActiveSource(false);
- } else {
- audioSystem.setIsActiveSource(true);
+ if (playback() == null) {
+ audioSystem.setActiveSource(audioSystem.getDeviceInfo().getLogicalAddress(),
+ physicalAddress, caller);
audioSystem.wakeUpIfActiveSource();
audioSystem.maySendActiveSource(source);
}
@@ -3294,24 +3286,21 @@
// and this method updates Active Source in all the device types sharing the same
// Physical Address.
protected void setAndBroadcastActiveSourceFromOneDeviceType(
- int sourceAddress, int physicalAddress) {
+ int sourceAddress, int physicalAddress, String caller) {
// If the device has both playback and audio system logical addresses,
// playback will claim active source. Otherwise audio system will.
HdmiCecLocalDevicePlayback playback = playback();
HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
if (playback != null) {
- playback.setIsActiveSource(true);
+ playback.setActiveSource(playback.getDeviceInfo().getLogicalAddress(), physicalAddress,
+ caller);
playback.wakeUpIfActiveSource();
playback.maySendActiveSource(sourceAddress);
- if (audioSystem != null) {
- audioSystem.setIsActiveSource(false);
- }
- } else {
- if (audioSystem != null) {
- audioSystem.setIsActiveSource(true);
- audioSystem.wakeUpIfActiveSource();
- audioSystem.maySendActiveSource(sourceAddress);
- }
+ } else if (audioSystem != null) {
+ audioSystem.setActiveSource(audioSystem.getDeviceInfo().getLogicalAddress(),
+ physicalAddress, caller);
+ audioSystem.wakeUpIfActiveSource();
+ audioSystem.maySendActiveSource(sourceAddress);
}
}
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 4962af1..e78a86c 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -85,7 +85,7 @@
// Because only source device can create this action, it's safe to cast.
HdmiCecLocalDeviceSource source = source();
source.mService.setAndBroadcastActiveSourceFromOneDeviceType(
- mTargetAddress, getSourcePath());
+ mTargetAddress, getSourcePath(), "OneTouchPlayAction#broadcastActiveSource()");
// When OneTouchPlay is called, client side should be responsible to send out the intent
// of which internal source, for example YouTube, it would like to switch to.
// Here we only update the active port and the active source records in the local
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index 0907e5d..acafda6 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -119,7 +119,8 @@
// claim Active Source and start to query TV system audio mode support.
if (audioSystem().mService.isPlaybackDevice()) {
audioSystem().mService.setAndBroadcastActiveSourceFromOneDeviceType(
- Constants.ADDR_BROADCAST, getSourcePath());
+ Constants.ADDR_BROADCAST, getSourcePath(),
+ "SystemAudioInitiationActionFromAvr#handleActiveSourceTimeout()");
mState = STATE_WAITING_FOR_TV_SUPPORT;
queryTvSystemAudioModeSupport();
} else {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 72734c4..227cdee 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -23,10 +23,10 @@
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
+import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
-import static com.android.server.location.LocationProviderManager.FASTEST_COARSE_INTERVAL_MS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -36,6 +36,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
+import android.app.compat.CompatChanges;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
@@ -82,21 +83,21 @@
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.location.LocationPermissions.PermissionLevel;
-import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
-import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.geofence.GeofenceManager;
import com.android.server.location.geofence.GeofenceProxy;
import com.android.server.location.gnss.GnssManagerService;
+import com.android.server.location.util.AlarmHelper;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppOpsHelper;
import com.android.server.location.util.Injector;
import com.android.server.location.util.LocationAttributionHelper;
+import com.android.server.location.util.LocationEventLog;
import com.android.server.location.util.LocationPermissionsHelper;
import com.android.server.location.util.LocationPowerSaveModeHelper;
import com.android.server.location.util.LocationUsageLogger;
import com.android.server.location.util.ScreenInteractiveHelper;
import com.android.server.location.util.SettingsHelper;
+import com.android.server.location.util.SystemAlarmHelper;
import com.android.server.location.util.SystemAppForegroundHelper;
import com.android.server.location.util.SystemAppOpsHelper;
import com.android.server.location.util.SystemLocationPermissionsHelper;
@@ -112,9 +113,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -417,6 +416,8 @@
Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
}
+ mInjector.getLocationEventLog().logLocationEnabled(userId, enabled);
+
Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
@@ -569,7 +570,7 @@
new IllegalArgumentException());
}
- request = validateAndSanitizeLocationRequest(request, permissionLevel);
+ request = validateLocationRequest(request);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -591,7 +592,7 @@
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateAndSanitizeLocationRequest(request, permissionLevel);
+ request = validateLocationRequest(request);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -600,8 +601,7 @@
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
- private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
- @PermissionLevel int permissionLevel) {
+ private LocationRequest validateLocationRequest(LocationRequest request) {
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
@@ -620,26 +620,20 @@
}
LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
- if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
- sanitized.setLowPower(false);
- }
- if (permissionLevel < PERMISSION_FINE) {
- switch (request.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- sanitized.setQuality(LocationRequest.POWER_LOW);
- break;
- }
- if (request.getIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.setIntervalMillis(FASTEST_COARSE_INTERVAL_MS);
+ if (CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
+ if (request.isLowPower()) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.LOCATION_HARDWARE,
+ "low power request requires " + permission.LOCATION_HARDWARE);
}
- if (request.getMinUpdateIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.clearMinUpdateIntervalMillis();
+ } else {
+ if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
+ != PERMISSION_GRANTED) {
+ sanitized.setLowPower(false);
}
}
+
if (request.getWorkSource() != null) {
if (request.getWorkSource().isEmpty()) {
sanitized.setWorkSource(null);
@@ -716,7 +710,7 @@
// clients in the system process must have an attribution tag set
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateAndSanitizeLocationRequest(request, permissionLevel);
+ request = validateLocationRequest(request);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -735,7 +729,7 @@
// use fine permission level to avoid creating unnecessary coarse locations
Location location = gpsManager.getLastLocationUnsafe(UserHandle.USER_ALL,
- PERMISSION_FINE, false);
+ PERMISSION_FINE, false, Long.MAX_VALUE);
if (location == null) {
return null;
}
@@ -1136,18 +1130,6 @@
mInjector.getSettingsHelper().dump(fd, ipw, args);
ipw.decreaseIndent();
- ipw.println("Historical Records by Provider:");
- ipw.increaseIndent();
- TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
- mInjector.getLocationRequestStatistics().statistics);
- for (Map.Entry<PackageProviderKey, PackageStatistics> entry
- : sorted.entrySet()) {
- ipw.println(entry.getKey() + ": " + entry.getValue());
- }
- ipw.decreaseIndent();
-
- mInjector.getLocationRequestStatistics().history.dump(ipw);
-
synchronized (mLock) {
if (mExtraLocationControllerPackage != null) {
ipw.println(
@@ -1175,6 +1157,13 @@
ipw.increaseIndent();
mGeofenceManager.dump(fd, ipw, args);
ipw.decreaseIndent();
+
+ ipw.println("Event Log:");
+ ipw.increaseIndent();
+ for (String log : mInjector.getLocationEventLog()) {
+ ipw.println(log);
+ }
+ ipw.decreaseIndent();
}
private class LocalService extends LocationManagerInternal {
@@ -1236,7 +1225,9 @@
private static class SystemInjector implements Injector {
+ private final LocationEventLog mLocationEventLog;
private final UserInfoHelper mUserInfoHelper;
+ private final AlarmHelper mAlarmHelper;
private final SystemAppOpsHelper mAppOpsHelper;
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
private final SystemSettingsHelper mSettingsHelper;
@@ -1245,20 +1236,21 @@
private final SystemScreenInteractiveHelper mScreenInteractiveHelper;
private final LocationAttributionHelper mLocationAttributionHelper;
private final LocationUsageLogger mLocationUsageLogger;
- private final LocationRequestStatistics mLocationRequestStatistics;
SystemInjector(Context context, UserInfoHelper userInfoHelper) {
+ mLocationEventLog = new LocationEventLog();
mUserInfoHelper = userInfoHelper;
+ mAlarmHelper = new SystemAlarmHelper(context);
mAppOpsHelper = new SystemAppOpsHelper(context);
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
mAppOpsHelper);
mSettingsHelper = new SystemSettingsHelper(context);
mAppForegroundHelper = new SystemAppForegroundHelper(context);
- mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context);
+ mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context,
+ mLocationEventLog);
mScreenInteractiveHelper = new SystemScreenInteractiveHelper(context);
mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper);
mLocationUsageLogger = new LocationUsageLogger();
- mLocationRequestStatistics = new LocationRequestStatistics();
}
void onSystemReady() {
@@ -1276,6 +1268,11 @@
}
@Override
+ public AlarmHelper getAlarmHelper() {
+ return mAlarmHelper;
+ }
+
+ @Override
public AppOpsHelper getAppOpsHelper() {
return mAppOpsHelper;
}
@@ -1316,8 +1313,8 @@
}
@Override
- public LocationRequestStatistics getLocationRequestStatistics() {
- return mLocationRequestStatistics;
+ public LocationEventLog getLocationEventLog() {
+ return mLocationEventLog;
}
}
}
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 138301a..48f8da4 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -16,13 +16,14 @@
package com.android.server.location;
-import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
-import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.app.compat.CompatChanges.isChangeEnabled;
+import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.PASSIVE_PROVIDER;
+import static android.location.LocationRequest.PASSIVE_INTERVAL;
import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
@@ -36,11 +37,11 @@
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+import static java.lang.Math.max;
import static java.lang.Math.min;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.annotation.Nullable;
-import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -88,11 +89,13 @@
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.listeners.ListenerMultiplexer;
import com.android.server.location.listeners.RemoteListenerRegistration;
+import com.android.server.location.util.AlarmHelper;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.util.AppOpsHelper;
import com.android.server.location.util.Injector;
import com.android.server.location.util.LocationAttributionHelper;
+import com.android.server.location.util.LocationEventLog;
import com.android.server.location.util.LocationPermissionsHelper;
import com.android.server.location.util.LocationPermissionsHelper.LocationPermissionsListener;
import com.android.server.location.util.LocationPowerSaveModeHelper;
@@ -118,12 +121,12 @@
LocationProviderManager.Registration, ProviderRequest> implements
AbstractLocationProvider.Listener {
- // fastest interval at which clients may receive coarse locations
- public static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
-
private static final String WAKELOCK_TAG = "*location*";
private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
+ // fastest interval at which clients may receive coarse locations
+ private static final long MIN_COARSE_INTERVAL_MS = 10 * 60 * 1000;
+
// max interval to be considered "high power" request
private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
@@ -133,8 +136,15 @@
// max timeout allowed for getting the current location
private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
- // max jitter allowed for fastest interval evaluation
- private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 100;
+ // max jitter allowed for min update interval as a percentage of the interval
+ private static final float FASTEST_INTERVAL_JITTER_PERCENTAGE = .10f;
+
+ // max absolute jitter allowed for min update interval evaluation
+ private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 5 * 1000;
+
+ // minimum amount of request delay in order to respect the delay, below this value the request
+ // will just be scheduled immediately
+ private static final long MIN_REQUEST_DELAY_MS = 30 * 1000;
protected interface LocationTransport {
@@ -221,6 +231,7 @@
/**
* Must be implemented to return the location this operation intends to deliver.
*/
+ @Nullable
Location getLocation();
}
@@ -266,6 +277,8 @@
+ getRequest());
}
+ mLocationEventLog.logProviderClientRegistered(mName, getIdentity(), super.getRequest());
+
// initialization order is important as there are ordering dependencies
mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
getIdentity());
@@ -285,6 +298,8 @@
onProviderListenerUnregister();
+ mLocationEventLog.logProviderClientUnregistered(mName, getIdentity());
+
if (D) {
Log.d(TAG, mName + " provider removed registration from " + getIdentity());
}
@@ -312,7 +327,7 @@
mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
}
onHighPowerUsageChanged();
- return null;
+ return onProviderListenerActive();
}
@Override
@@ -325,6 +340,22 @@
if (!getRequest().isHiddenFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
+ return onProviderListenerInactive();
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onActive()}.
+ */
+ @GuardedBy("mLock")
+ protected LocationListenerOperation onProviderListenerActive() {
+ return null;
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onInactive()} ()}.
+ */
+ @GuardedBy("mLock")
+ protected LocationListenerOperation onProviderListenerInactive() {
return null;
}
@@ -333,6 +364,14 @@
return mProviderLocationRequest;
}
+ @GuardedBy("mLock")
+ final void initializeLastLocation(@Nullable Location location) {
+ if (mLastLocation == null) {
+ mLastLocation = location;
+ }
+ }
+
+ @GuardedBy("mLock")
public final Location getLastDeliveredLocation() {
return mLastLocation;
}
@@ -465,9 +504,27 @@
}
private LocationRequest calculateProviderLocationRequest() {
- LocationRequest.Builder builder = new LocationRequest.Builder(super.getRequest());
+ LocationRequest baseRequest = super.getRequest();
+ LocationRequest.Builder builder = new LocationRequest.Builder(baseRequest);
- if (super.getRequest().isLocationSettingsIgnored()) {
+ if (mPermissionLevel < PERMISSION_FINE) {
+ switch (baseRequest.getQuality()) {
+ case LocationRequest.ACCURACY_FINE:
+ builder.setQuality(LocationRequest.ACCURACY_BLOCK);
+ break;
+ case LocationRequest.POWER_HIGH:
+ builder.setQuality(LocationRequest.POWER_LOW);
+ break;
+ }
+ if (baseRequest.getIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
+ builder.setIntervalMillis(MIN_COARSE_INTERVAL_MS);
+ }
+ if (baseRequest.getMinUpdateIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
+ builder.clearMinUpdateIntervalMillis();
+ }
+ }
+
+ if (baseRequest.isLocationSettingsIgnored()) {
// if we are not currently allowed use location settings ignored, disable it
if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
@@ -476,10 +533,10 @@
}
}
- if (!super.getRequest().isLocationSettingsIgnored() && !isThrottlingExempt()) {
+ if (!baseRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
// throttle in the background
if (!mForeground) {
- builder.setIntervalMillis(Math.max(super.getRequest().getIntervalMillis(),
+ builder.setIntervalMillis(max(baseRequest.getIntervalMillis(),
mSettingsHelper.getBackgroundThrottleIntervalMs()));
}
}
@@ -534,7 +591,7 @@
}
protected abstract class LocationRegistration extends Registration implements
- AlarmManager.OnAlarmListener, ProviderEnabledListener {
+ OnAlarmListener, ProviderEnabledListener {
private final PowerManager.WakeLock mWakeLock;
@@ -561,17 +618,15 @@
@GuardedBy("mLock")
@Override
protected final void onProviderListenerRegister() {
- mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
- SystemClock.elapsedRealtime());
+ long registerTimeMs = SystemClock.elapsedRealtime();
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(registerTimeMs);
// add alarm for expiration
- if (mExpirationRealtimeMs < SystemClock.elapsedRealtime()) {
- remove();
+ if (mExpirationRealtimeMs <= registerTimeMs) {
+ onAlarm();
} else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
- AlarmManager alarmManager = Objects.requireNonNull(
- mContext.getSystemService(AlarmManager.class));
- alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
- 0, this, FgThread.getHandler(), getWorkSource());
+ mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
+ getWorkSource());
}
// start listening for provider enabled/disabled events
@@ -594,9 +649,7 @@
// remove alarm for expiration
if (mExpirationRealtimeMs < Long.MAX_VALUE) {
- AlarmManager alarmManager = Objects.requireNonNull(
- mContext.getSystemService(AlarmManager.class));
- alarmManager.cancel(this);
+ mAlarmHelper.cancel(this);
}
onLocationListenerUnregister();
@@ -614,6 +667,39 @@
@GuardedBy("mLock")
protected void onLocationListenerUnregister() {}
+ @GuardedBy("mLock")
+ @Override
+ protected final LocationListenerOperation onProviderListenerActive() {
+ // a new registration may not get a location immediately, the provider request may be
+ // delayed. therefore we deliver a historical location if available. since delivering an
+ // older location could be considered a breaking change for some applications, we only
+ // do so for apps targeting S+.
+ if (isChangeEnabled(DELIVER_HISTORICAL_LOCATIONS, getIdentity().getUid())) {
+ long maxLocationAgeMs = getRequest().getIntervalMillis();
+ Location lastDeliveredLocation = getLastDeliveredLocation();
+ if (lastDeliveredLocation != null) {
+ // ensure that location is fresher than the last delivered location
+ maxLocationAgeMs = min(maxLocationAgeMs,
+ lastDeliveredLocation.getElapsedRealtimeAgeMillis() - 1);
+ }
+
+ // requests are never delayed less than MIN_REQUEST_DELAY_MS, so it only makes sense
+ // to deliver historical locations to clients with a last location older than that
+ if (maxLocationAgeMs > MIN_REQUEST_DELAY_MS) {
+ Location lastLocation = getLastLocationUnsafe(
+ getIdentity().getUserId(),
+ PERMISSION_FINE, // acceptLocationChange() handles coarsening this
+ getRequest().isLocationSettingsIgnored(),
+ maxLocationAgeMs);
+ if (lastLocation != null) {
+ return acceptLocationChange(lastLocation);
+ }
+ }
+ }
+
+ return null;
+ }
+
@Override
public void onAlarm() {
if (D) {
@@ -624,6 +710,8 @@
synchronized (mLock) {
remove();
+ // no need to remove alarm after it's fired
+ mExpirationRealtimeMs = Long.MAX_VALUE;
}
}
@@ -658,11 +746,11 @@
Location lastDeliveredLocation = getLastDeliveredLocation();
if (lastDeliveredLocation != null) {
// check fastest interval
- long deltaMs = NANOSECONDS.toMillis(
- location.getElapsedRealtimeNanos()
- - lastDeliveredLocation.getElapsedRealtimeNanos());
- if (deltaMs < getRequest().getMinUpdateIntervalMillis()
- - MAX_FASTEST_INTERVAL_JITTER_MS) {
+ long deltaMs = location.getElapsedRealtimeMillis()
+ - lastDeliveredLocation.getElapsedRealtimeMillis();
+ long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
+ * getRequest().getIntervalMillis()), MAX_FASTEST_INTERVAL_JITTER_MS);
+ if (deltaMs < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
return null;
}
@@ -710,6 +798,7 @@
listener.deliverOnLocationChanged(deliveryLocation,
location.isFromMockProvider() ? null : mWakeLock::release);
+ mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
}
@Override
@@ -871,7 +960,7 @@
}
protected final class GetCurrentLocationListenerRegistration extends Registration implements
- IBinder.DeathRecipient, ProviderEnabledListener, AlarmManager.OnAlarmListener {
+ IBinder.DeathRecipient, ProviderEnabledListener, OnAlarmListener {
private volatile LocationTransport mTransport;
@@ -902,15 +991,15 @@
remove();
}
- mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
- SystemClock.elapsedRealtime());
+ long registerTimeMs = SystemClock.elapsedRealtime();
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(registerTimeMs);
// add alarm for expiration
- if (mExpirationRealtimeMs < Long.MAX_VALUE) {
- AlarmManager alarmManager = Objects.requireNonNull(
- mContext.getSystemService(AlarmManager.class));
- alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
- 0, this, FgThread.getHandler(), getWorkSource());
+ if (mExpirationRealtimeMs <= registerTimeMs) {
+ onAlarm();
+ } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
+ getWorkSource());
}
// if this request is ignoring location settings, then we don't want to immediately fail
@@ -935,9 +1024,7 @@
// remove alarm for expiration
if (mExpirationRealtimeMs < Long.MAX_VALUE) {
- AlarmManager alarmManager = Objects.requireNonNull(
- mContext.getSystemService(AlarmManager.class));
- alarmManager.cancel(this);
+ mAlarmHelper.cancel(this);
}
((IBinder) getKey()).unlinkToDeath(this, 0);
@@ -953,6 +1040,8 @@
synchronized (mLock) {
deliverLocation(null);
+ // no need to remove alarm after it's fired
+ mExpirationRealtimeMs = Long.MAX_VALUE;
}
}
@@ -964,6 +1053,12 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
+ // check expiration time - alarm is not guaranteed to go off at the right time,
+ // especially for short intervals
+ if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+ fineLocation = null;
+ }
+
// lastly - note app ops
Location location;
if (fineLocation == null) {
@@ -1006,6 +1101,7 @@
// we currently don't hold a wakelock for getCurrentLocation deliveries
try {
listener.deliverOnLocationChanged(deliveryLocation, null);
+ mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
} catch (Exception exception) {
if (exception instanceof RemoteException) {
Log.w(TAG, "registration " + this + " failed", exception);
@@ -1077,6 +1173,7 @@
protected final LocationManagerInternal mLocationManagerInternal;
protected final SettingsHelper mSettingsHelper;
protected final UserInfoHelper mUserInfoHelper;
+ protected final AlarmHelper mAlarmHelper;
protected final AppOpsHelper mAppOpsHelper;
protected final LocationPermissionsHelper mLocationPermissionsHelper;
protected final AppForegroundHelper mAppForegroundHelper;
@@ -1085,7 +1182,7 @@
protected final LocationAttributionHelper mLocationAttributionHelper;
protected final LocationUsageLogger mLocationUsageLogger;
protected final LocationFudger mLocationFudger;
- protected final LocationRequestStatistics mLocationRequestStatistics;
+ protected final LocationEventLog mLocationEventLog;
private final UserListener mUserChangedListener = this::onUserChanged;
private final UserSettingChangedListener mLocationEnabledChangedListener =
@@ -1120,6 +1217,9 @@
// acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
protected final MockableLocationProvider mProvider;
+ @GuardedBy("mLock")
+ @Nullable private OnAlarmListener mDelayedRegister;
+
LocationProviderManager(Context context, Injector injector, String name,
@Nullable PassiveLocationProviderManager passiveManager) {
mContext = context;
@@ -1135,6 +1235,7 @@
LocalServices.getService(LocationManagerInternal.class));
mSettingsHelper = injector.getSettingsHelper();
mUserInfoHelper = injector.getUserInfoHelper();
+ mAlarmHelper = injector.getAlarmHelper();
mAppOpsHelper = injector.getAppOpsHelper();
mLocationPermissionsHelper = injector.getLocationPermissionsHelper();
mAppForegroundHelper = injector.getAppForegroundHelper();
@@ -1142,7 +1243,7 @@
mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
mLocationAttributionHelper = injector.getLocationAttributionHelper();
mLocationUsageLogger = injector.getLocationUsageLogger();
- mLocationRequestStatistics = injector.getLocationRequestStatistics();
+ mLocationEventLog = injector.getLocationEventLog();
mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
// initialize last since this lets our reference escape
@@ -1260,6 +1361,8 @@
synchronized (mLock) {
Preconditions.checkState(mStarted);
+ mLocationEventLog.logProviderMocked(mName, provider != null);
+
long identity = Binder.clearCallingIdentity();
try {
mProvider.setMockProvider(provider);
@@ -1344,7 +1447,7 @@
}
Location location = getLastLocationUnsafe(identity.getUserId(), permissionLevel,
- ignoreLocationSettings);
+ ignoreLocationSettings, Long.MAX_VALUE);
// we don't note op here because we don't know what the client intends to do with the
// location, the client is responsible for noting if necessary
@@ -1364,13 +1467,14 @@
*/
@Nullable
public Location getLastLocationUnsafe(int userId, @PermissionLevel int permissionLevel,
- boolean ignoreLocationSettings) {
+ boolean ignoreLocationSettings, long maximumAgeMs) {
if (userId == UserHandle.USER_ALL) {
+ // find the most recent location across all users
Location lastLocation = null;
final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
for (int i = 0; i < runningUserIds.length; i++) {
Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
- ignoreLocationSettings);
+ ignoreLocationSettings, maximumAgeMs);
if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
> lastLocation.getElapsedRealtimeNanos())) {
lastLocation = next;
@@ -1381,18 +1485,30 @@
Preconditions.checkArgument(userId >= 0);
+ Location location;
synchronized (mLock) {
LastLocation lastLocation = mLastLocations.get(userId);
if (lastLocation == null) {
- return null;
+ location = null;
+ } else {
+ location = lastLocation.get(permissionLevel, ignoreLocationSettings);
}
- return lastLocation.get(permissionLevel, ignoreLocationSettings);
}
+
+ if (location == null) {
+ return null;
+ }
+
+ if (location.getElapsedRealtimeAgeMillis() > maximumAgeMs) {
+ return null;
+ }
+
+ return location;
}
public void injectLastLocation(Location location, int userId) {
synchronized (mLock) {
- if (getLastLocationUnsafe(userId, PERMISSION_FINE, false) == null) {
+ if (getLastLocationUnsafe(userId, PERMISSION_FINE, false, Long.MAX_VALUE) == null) {
setLastLocation(location, userId);
}
}
@@ -1455,22 +1571,14 @@
return null;
}
- Location lastLocation = getLastLocationUnsafe(callerIdentity.getUserId(),
- permissionLevel, request.isLocationSettingsIgnored());
+ Location lastLocation = getLastLocationUnsafe(
+ callerIdentity.getUserId(),
+ permissionLevel,
+ request.isLocationSettingsIgnored(),
+ MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
- long locationAgeMs = NANOSECONDS.toMillis(
- SystemClock.elapsedRealtimeNanos()
- - lastLocation.getElapsedRealtimeNanos());
- if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
- registration.deliverLocation(lastLocation);
- return null;
- }
-
- if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())
- && locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
- registration.deliverLocation(null);
- return null;
- }
+ registration.deliverLocation(lastLocation);
+ return null;
}
// if last location isn't good enough then we add a location request
@@ -1618,13 +1726,16 @@
key instanceof PendingIntent,
/* geofence= */ key instanceof IBinder,
null, registration.isForeground());
+ }
- mLocationRequestStatistics.startRequesting(
- registration.getIdentity().getPackageName(),
- registration.getIdentity().getAttributionTag(),
- mName,
- registration.getRequest().getIntervalMillis(),
- registration.isForeground());
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegistrationReplaced(Object key, Registration oldRegistration,
+ Registration newRegistration) {
+ // by saving the last delivered location state we are able to potentially delay the
+ // resulting provider request longer and save additional power
+ newRegistration.initializeLastLocation(oldRegistration.getLastDeliveredLocation());
+ super.onRegistrationReplaced(key, oldRegistration, newRegistration);
}
@GuardedBy("mLock")
@@ -1634,11 +1745,6 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- mLocationRequestStatistics.stopRequesting(
- registration.getIdentity().getPackageName(),
- registration.getIdentity().getAttributionTag(),
- mName);
-
mLocationUsageLogger.logLocationApiUsage(
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
@@ -1652,21 +1758,68 @@
@GuardedBy("mLock")
@Override
- protected boolean registerWithService(ProviderRequest mergedRequest,
+ protected boolean registerWithService(ProviderRequest request,
Collection<Registration> registrations) {
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkState(Thread.holdsLock(mLock));
- }
-
- mProvider.setRequest(mergedRequest);
- return true;
+ return reregisterWithService(EMPTY_REQUEST, request, registrations);
}
@GuardedBy("mLock")
@Override
protected boolean reregisterWithService(ProviderRequest oldRequest,
ProviderRequest newRequest, Collection<Registration> registrations) {
- return registerWithService(newRequest, registrations);
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (mDelayedRegister != null) {
+ mAlarmHelper.cancel(mDelayedRegister);
+ mDelayedRegister = null;
+ }
+
+ // calculate how long the new request should be delayed before sending it off to the
+ // provider, under the assumption that once we send the request off, the provider will
+ // immediately attempt to deliver a new location satisfying that request.
+ long delayMs;
+ if (!oldRequest.isLocationSettingsIgnored() && newRequest.isLocationSettingsIgnored()) {
+ delayMs = 0;
+ } else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
+ // if the interval has increased, tell the provider immediately, so it can save power
+ // (even though technically this could burn extra power in the short term by producing
+ // an extra location - the provider itself is free to detect an increasing interval and
+ // delay its own location)
+ delayMs = 0;
+ } else {
+ delayMs = calculateRequestDelayMillis(newRequest.getIntervalMillis(), registrations);
+ }
+
+ // the delay should never exceed the new interval
+ Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis());
+
+ if (delayMs < MIN_REQUEST_DELAY_MS) {
+ mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
+ mProvider.setRequest(newRequest);
+ } else {
+ if (D) {
+ Log.d(TAG, mName + " provider delaying request update " + newRequest + " by "
+ + TimeUtils.formatDuration(delayMs));
+ }
+
+ mDelayedRegister = new OnAlarmListener() {
+ @Override
+ public void onAlarm() {
+ synchronized (mLock) {
+ if (mDelayedRegister == this) {
+ mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
+ mProvider.setRequest(newRequest);
+ mDelayedRegister = null;
+ }
+ }
+ }
+ };
+ mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, newRequest.getWorkSource());
+ }
+
+ return true;
}
@GuardedBy("mLock")
@@ -1676,6 +1829,7 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
+ mLocationEventLog.logProviderUpdateRequest(mName, EMPTY_REQUEST);
mProvider.setRequest(EMPTY_REQUEST);
}
@@ -1733,42 +1887,40 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- ArrayList<Registration> providerRegistrations = new ArrayList<>(registrations.size());
-
long intervalMs = Long.MAX_VALUE;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
ArrayList<LocationRequest> locationRequests = new ArrayList<>(registrations.size());
- for (Registration registration : registrations) {
- LocationRequest locationRequest = registration.getRequest();
- // passive requests do not contribute to the provider
- if (locationRequest.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
+ for (Registration registration : registrations) {
+ LocationRequest request = registration.getRequest();
+
+ // passive requests do not contribute to the provider request
+ if (request.getIntervalMillis() == PASSIVE_INTERVAL) {
continue;
}
- providerRegistrations.add(registration);
- intervalMs = min(locationRequest.getIntervalMillis(), intervalMs);
- locationSettingsIgnored |= locationRequest.isLocationSettingsIgnored();
- lowPower &= locationRequest.isLowPower();
- locationRequests.add(locationRequest);
+ intervalMs = min(request.getIntervalMillis(), intervalMs);
+ locationSettingsIgnored |= request.isLocationSettingsIgnored();
+ lowPower &= request.isLowPower();
+ locationRequests.add(request);
}
// calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
// interval slightly higher that the minimum interval, and spread the blame across all
// contributing registrations under that threshold (since worksource does not allow us to
// represent differing power blame ratios).
- WorkSource workSource = new WorkSource();
long thresholdIntervalMs = (intervalMs + 1000) * 3 / 2;
- if (thresholdIntervalMs < 0) {
- // handle overflow by setting to one below the passive interval
- thresholdIntervalMs = Long.MAX_VALUE - 1;
+ if (thresholdIntervalMs < 0 || thresholdIntervalMs >= PASSIVE_INTERVAL) {
+ // check for and handle overflow by setting to one below the passive interval so passive
+ // requests are automatically skipped
+ thresholdIntervalMs = PASSIVE_INTERVAL - 1;
}
- final int providerRegistrationsSize = providerRegistrations.size();
- for (int i = 0; i < providerRegistrationsSize; i++) {
- Registration registration = providerRegistrations.get(i);
+
+ WorkSource workSource = new WorkSource();
+ for (Registration registration : registrations) {
if (registration.getRequest().getIntervalMillis() <= thresholdIntervalMs) {
- workSource.add(providerRegistrations.get(i).getWorkSource());
+ workSource.add(registration.getWorkSource());
}
}
@@ -1781,6 +1933,47 @@
.build();
}
+ @GuardedBy("mLock")
+ protected long calculateRequestDelayMillis(long newIntervalMs,
+ Collection<Registration> registrations) {
+ // calculate the minimum delay across all registrations, ensuring that it is not more than
+ // the requested interval
+ long delayMs = newIntervalMs;
+ for (Registration registration : registrations) {
+ if (delayMs == 0) {
+ break;
+ }
+
+ LocationRequest locationRequest = registration.getRequest();
+ Location last = registration.getLastDeliveredLocation();
+
+ if (last == null && !locationRequest.isLocationSettingsIgnored()) {
+ // if this request has never gotten any location and it's not ignoring location
+ // settings, then we pretend that this request has gotten the last applicable cached
+ // location for our calculations instead. this prevents spammy add/remove behavior
+ last = getLastLocationUnsafe(
+ registration.getIdentity().getUserId(),
+ PERMISSION_FINE,
+ false,
+ locationRequest.getIntervalMillis());
+ }
+
+ long registrationDelayMs;
+ if (last == null) {
+ // if this request has never gotten any location then there's no delay
+ registrationDelayMs = 0;
+ } else {
+ // otherwise the delay is the amount of time until the next location is expected
+ registrationDelayMs = max(0,
+ locationRequest.getIntervalMillis() - last.getElapsedRealtimeAgeMillis());
+ }
+
+ delayMs = min(delayMs, registrationDelayMs);
+ }
+
+ return delayMs;
+ }
+
private void onUserChanged(int userId, int change) {
synchronized (mLock) {
switch (change) {
@@ -1905,16 +2098,21 @@
return;
}
+ if (mPassiveManager != null) {
+ // don't log location received for passive provider because it's spammy
+ mLocationEventLog.logProviderReceivedLocation(mName);
+ }
+
// update last location
setLastLocation(location, UserHandle.USER_ALL);
+ // attempt listener delivery
+ deliverToListeners(registration -> registration.acceptLocationChange(location));
+
// notify passive provider
if (mPassiveManager != null) {
mPassiveManager.updateLocation(location);
}
-
- // attempt listener delivery
- deliverToListeners(registration -> registration.acceptLocationChange(location));
}
@GuardedBy("mLock")
@@ -2006,8 +2204,12 @@
mEnabled.put(userId, enabled);
- if (D) {
- Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
+ // don't log unknown -> false transitions for brevity
+ if (wasEnabled != null || enabled) {
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
+ }
+ mLocationEventLog.logProviderEnabled(mName, userId, enabled);
}
// clear last locations if we become disabled
@@ -2068,7 +2270,7 @@
ipw.increaseIndent();
}
ipw.print("last location=");
- ipw.println(getLastLocationUnsafe(userId, PERMISSION_FINE, false));
+ ipw.println(getLastLocationUnsafe(userId, PERMISSION_FINE, false, Long.MAX_VALUE));
ipw.print("enabled=");
ipw.println(isEnabled(userId));
if (userIds.length != 1) {
@@ -2082,6 +2284,11 @@
ipw.decreaseIndent();
}
+ @Override
+ protected String getServiceState() {
+ return mProvider.getCurrentRequest().toString();
+ }
+
private static class LastLocation {
@Nullable private Location mFineLocation;
@@ -2126,24 +2333,37 @@
}
}
- public void set(Location location, Location coarseLocation) {
- mFineLocation = location;
+ public void set(Location fineLocation, Location coarseLocation) {
+ mFineLocation = calculateNextFine(mFineLocation, fineLocation);
mCoarseLocation = calculateNextCoarse(mCoarseLocation, coarseLocation);
}
- public void setBypass(Location location, Location coarseLocation) {
- mFineBypassLocation = location;
+ public void setBypass(Location fineLocation, Location coarseLocation) {
+ mFineBypassLocation = calculateNextFine(mFineBypassLocation, fineLocation);
mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, coarseLocation);
}
+ private Location calculateNextFine(@Nullable Location oldFine, Location newFine) {
+ if (oldFine == null) {
+ return newFine;
+ }
+
+ // update last fine interval only if more recent
+ if (newFine.getElapsedRealtimeNanos() > oldFine.getElapsedRealtimeNanos()) {
+ return newFine;
+ } else {
+ return oldFine;
+ }
+ }
+
private Location calculateNextCoarse(@Nullable Location oldCoarse, Location newCoarse) {
if (oldCoarse == null) {
return newCoarse;
}
+
// update last coarse interval only if enough time has passed
- long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
- - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
- if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
+ if (newCoarse.getElapsedRealtimeNanos() - MIN_COARSE_INTERVAL_MS
+ > oldCoarse.getElapsedRealtimeNanos()) {
return newCoarse;
} else {
return oldCoarse;
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
deleted file mode 100644
index 4984e63..0000000
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ /dev/null
@@ -1,449 +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 com.android.server.location;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.TimeUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Objects;
-
-/**
- * Holds statistics for location requests (active requests by provider).
- *
- * <p>Must be externally synchronized.
- */
-public class LocationRequestStatistics {
- private static final String TAG = "LocationStats";
-
- // Maps package name and provider to location request statistics.
- public final HashMap<PackageProviderKey, PackageStatistics> statistics
- = new HashMap<PackageProviderKey, PackageStatistics>();
-
- public final RequestSummaryLimitedHistory history = new RequestSummaryLimitedHistory();
-
- /**
- * Signals that a package has started requesting locations.
- *
- * @param packageName Name of package that has requested locations.
- * @param featureId Feature id associated with the request.
- * @param providerName Name of provider that is requested (e.g. "gps").
- * @param intervalMs The interval that is requested in ms.
- */
- public void startRequesting(String packageName, @Nullable String featureId, String providerName,
- long intervalMs, boolean isForeground) {
- PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName);
- PackageStatistics stats = statistics.get(key);
- if (stats == null) {
- stats = new PackageStatistics();
- statistics.put(key, stats);
- }
- stats.startRequesting(intervalMs);
- stats.updateForeground(isForeground);
- history.addRequest(packageName, featureId, providerName, intervalMs);
- }
-
- /**
- * Signals that a package has stopped requesting locations.
- *
- * @param packageName Name of package that has stopped requesting locations.
- * @param featureId Feature id associated with the request.
- * @param providerName Provider that is no longer being requested.
- */
- public void stopRequesting(String packageName, @Nullable String featureId,
- String providerName) {
- PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName);
- PackageStatistics stats = statistics.get(key);
- if (stats != null) {
- stats.stopRequesting();
- }
- history.removeRequest(packageName, featureId, providerName);
- }
-
- /**
- * Signals that a package possibly switched background/foreground.
- *
- * @param packageName Name of package that has stopped requesting locations.
- * @param featureId Feature id associated with the request.
- * @param providerName Provider that is no longer being requested.
- */
- public void updateForeground(String packageName, @Nullable String featureId,
- String providerName, boolean isForeground) {
- PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName);
- PackageStatistics stats = statistics.get(key);
- if (stats != null) {
- stats.updateForeground(isForeground);
- }
- }
-
- /**
- * A key that holds package, feature id, and provider names.
- */
- public static class PackageProviderKey implements Comparable<PackageProviderKey> {
- /**
- * Name of package requesting location.
- */
- public final String mPackageName;
- /**
- * Feature id associated with the request, which can be used to attribute location access to
- * different parts of the application.
- */
- @Nullable
- public final String mFeatureId;
- /**
- * Name of provider being requested (e.g. "gps").
- */
- public final String mProviderName;
-
- PackageProviderKey(String packageName, @Nullable String featureId, String providerName) {
- this.mPackageName = packageName;
- this.mFeatureId = featureId;
- this.mProviderName = providerName;
- }
-
- @NonNull
- @Override
- public String toString() {
- return mProviderName + ": " + mPackageName
- + (mFeatureId == null ? "" : ": " + mFeatureId);
- }
-
- /**
- * Sort by provider, then package, then feature
- */
- @Override
- public int compareTo(PackageProviderKey other) {
- final int providerCompare = mProviderName.compareTo(other.mProviderName);
- if (providerCompare != 0) {
- return providerCompare;
- }
-
- final int packageCompare = mPackageName.compareTo(other.mPackageName);
- if (packageCompare != 0) {
- return packageCompare;
- }
-
- return Objects.compare(mFeatureId, other.mFeatureId, Comparator
- .nullsFirst(String::compareTo));
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof PackageProviderKey)) {
- return false;
- }
-
- PackageProviderKey otherKey = (PackageProviderKey) other;
- return mPackageName.equals(otherKey.mPackageName)
- && mProviderName.equals(otherKey.mProviderName)
- && Objects.equals(mFeatureId, otherKey.mFeatureId);
- }
-
- @Override
- public int hashCode() {
- int hash = mPackageName.hashCode() + 31 * mProviderName.hashCode();
- if (mFeatureId != null) {
- hash += mFeatureId.hashCode() + 31 * hash;
- }
- return hash;
- }
- }
-
- /**
- * A data structure to hold past requests
- */
- public static class RequestSummaryLimitedHistory {
- @VisibleForTesting
- static final int MAX_SIZE = 100;
-
- final ArrayList<RequestSummary> mList = new ArrayList<>(MAX_SIZE);
-
- /**
- * Append an added location request to the history
- */
- @VisibleForTesting
- void addRequest(String packageName, @Nullable String featureId, String providerName,
- long intervalMs) {
- addRequestSummary(new RequestSummary(packageName, featureId, providerName, intervalMs));
- }
-
- /**
- * Append a removed location request to the history
- */
- @VisibleForTesting
- void removeRequest(String packageName, @Nullable String featureId, String providerName) {
- addRequestSummary(new RequestSummary(
- packageName, featureId, providerName, RequestSummary.REQUEST_ENDED_INTERVAL));
- }
-
- private void addRequestSummary(RequestSummary summary) {
- while (mList.size() >= MAX_SIZE) {
- mList.remove(0);
- }
- mList.add(summary);
- }
-
- /**
- * Dump history to a printwriter (for dumpsys location)
- */
- public void dump(IndentingPrintWriter ipw) {
- long systemElapsedOffsetMillis = System.currentTimeMillis()
- - SystemClock.elapsedRealtime();
-
- ipw.println("Last Several Location Requests:");
- ipw.increaseIndent();
-
- for (RequestSummary requestSummary : mList) {
- requestSummary.dump(ipw, systemElapsedOffsetMillis);
- }
-
- ipw.decreaseIndent();
- }
- }
-
- /**
- * A data structure to hold a single request
- */
- static class RequestSummary {
- /**
- * Name of package requesting location.
- */
- private final String mPackageName;
-
- /**
- * Feature id associated with the request for identifying subsystem of an application.
- */
- @Nullable
- private final String mFeatureId;
- /**
- * Name of provider being requested (e.g. "gps").
- */
- private final String mProviderName;
- /**
- * Interval Requested, or REQUEST_ENDED_INTERVAL indicating request has ended
- */
- private final long mIntervalMillis;
- /**
- * Elapsed time of request
- */
- private final long mElapsedRealtimeMillis;
-
- /**
- * Placeholder for requested ending (other values indicate request started/changed)
- */
- static final long REQUEST_ENDED_INTERVAL = -1;
-
- RequestSummary(String packageName, @Nullable String featureId, String providerName,
- long intervalMillis) {
- this.mPackageName = packageName;
- this.mFeatureId = featureId;
- this.mProviderName = providerName;
- this.mIntervalMillis = intervalMillis;
- this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
- }
-
- void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
- StringBuilder s = new StringBuilder();
- long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
- s.append("At ").append(TimeUtils.logTimeOfDay(systemTimeMillis)).append(": ")
- .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
- .append(String.format("%7s", mProviderName)).append(" request from ")
- .append(mPackageName);
- if (mFeatureId != null) {
- s.append(" with feature ").append(mFeatureId);
- }
- if (mIntervalMillis != REQUEST_ENDED_INTERVAL) {
- s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds");
- }
- ipw.println(s);
- }
- }
-
- /**
- * Usage statistics for a package/provider pair.
- */
- public static class PackageStatistics {
- // Time when this package first requested location.
- private final long mInitialElapsedTimeMs;
- // Number of active location requests this package currently has.
- private int mNumActiveRequests;
- // Time when this package most recently went from not requesting location to requesting.
- private long mLastActivitationElapsedTimeMs;
- // The fastest interval this package has ever requested.
- private long mFastestIntervalMs;
- // The slowest interval this package has ever requested.
- private long mSlowestIntervalMs;
- // The total time this app has requested location (not including currently running
- // requests).
- private long mTotalDurationMs;
-
- // Time when this package most recently went to foreground, requesting location. 0 means
- // not currently in foreground.
- private long mLastForegroundElapsedTimeMs;
- // The time this app has requested location (not including currently running requests),
- // while in foreground.
- private long mForegroundDurationMs;
-
- // Time when package last went dormant (stopped requesting location)
- private long mLastStopElapsedTimeMs;
-
- private PackageStatistics() {
- mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
- mNumActiveRequests = 0;
- mTotalDurationMs = 0;
- mFastestIntervalMs = Long.MAX_VALUE;
- mSlowestIntervalMs = 0;
- mForegroundDurationMs = 0;
- mLastForegroundElapsedTimeMs = 0;
- mLastStopElapsedTimeMs = 0;
- }
-
- private void startRequesting(long intervalMs) {
- if (mNumActiveRequests == 0) {
- mLastActivitationElapsedTimeMs = SystemClock.elapsedRealtime();
- }
-
- if (intervalMs < mFastestIntervalMs) {
- mFastestIntervalMs = intervalMs;
- }
-
- if (intervalMs > mSlowestIntervalMs) {
- mSlowestIntervalMs = intervalMs;
- }
-
- mNumActiveRequests++;
- }
-
- private void updateForeground(boolean isForeground) {
- long nowElapsedTimeMs = SystemClock.elapsedRealtime();
- // if previous interval was foreground, accumulate before resetting start
- if (mLastForegroundElapsedTimeMs != 0) {
- mForegroundDurationMs += (nowElapsedTimeMs - mLastForegroundElapsedTimeMs);
- }
- mLastForegroundElapsedTimeMs = isForeground ? nowElapsedTimeMs : 0;
- }
-
- private void stopRequesting() {
- if (mNumActiveRequests <= 0) {
- // Shouldn't be a possible code path
- Log.e(TAG, "Reference counting corrupted in usage statistics.");
- return;
- }
-
- mNumActiveRequests--;
- if (mNumActiveRequests == 0) {
- mLastStopElapsedTimeMs = SystemClock.elapsedRealtime();
- long lastDurationMs = mLastStopElapsedTimeMs - mLastActivitationElapsedTimeMs;
- mTotalDurationMs += lastDurationMs;
- updateForeground(false);
- }
- }
-
- /**
- * Returns the duration that this request has been active.
- */
- public long getDurationMs() {
- long currentDurationMs = mTotalDurationMs;
- if (mNumActiveRequests > 0) {
- currentDurationMs
- += SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
- }
- return currentDurationMs;
- }
-
- /**
- * Returns the duration that this request has been active.
- */
- public long getForegroundDurationMs() {
- long currentDurationMs = mForegroundDurationMs;
- if (mLastForegroundElapsedTimeMs != 0) {
- currentDurationMs
- += SystemClock.elapsedRealtime() - mLastForegroundElapsedTimeMs;
- }
- return currentDurationMs;
- }
-
- /**
- * Returns the time since the initial request in ms.
- */
- public long getTimeSinceFirstRequestMs() {
- return SystemClock.elapsedRealtime() - mInitialElapsedTimeMs;
- }
-
- /**
- * Returns the time since the last request stopped in ms.
- */
- public long getTimeSinceLastRequestStoppedMs() {
- return SystemClock.elapsedRealtime() - mLastStopElapsedTimeMs;
- }
-
- /**
- * Returns the fastest interval that has been tracked.
- */
- public long getFastestIntervalMs() {
- return mFastestIntervalMs;
- }
-
- /**
- * Returns the slowest interval that has been tracked.
- */
- public long getSlowestIntervalMs() {
- return mSlowestIntervalMs;
- }
-
- /**
- * Returns true if a request is active for these tracked statistics.
- */
- public boolean isActive() {
- return mNumActiveRequests > 0;
- }
-
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder();
- if (mFastestIntervalMs == mSlowestIntervalMs) {
- s.append("Interval ").append(mFastestIntervalMs / 1000).append(" seconds");
- } else {
- s.append("Min interval ").append(mFastestIntervalMs / 1000).append(" seconds");
- s.append(": Max interval ").append(mSlowestIntervalMs / 1000).append(" seconds");
- }
- s.append(": Duration requested ")
- .append((getDurationMs() / 1000) / 60)
- .append(" total, ")
- .append((getForegroundDurationMs() / 1000) / 60)
- .append(" foreground, out of the last ")
- .append((getTimeSinceFirstRequestMs() / 1000) / 60)
- .append(" minutes");
- if (isActive()) {
- s.append(": Currently active");
- } else {
- s.append(": Last active ")
- .append((getTimeSinceLastRequestStoppedMs() / 1000) / 60)
- .append(" minutes ago");
- }
- return s.toString();
- }
- }
-}
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index afeb644..2870d41 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -20,14 +20,12 @@
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
-import android.location.LocationRequest;
import android.os.Binder;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
import com.android.server.location.util.Injector;
-import java.util.ArrayList;
import java.util.Collection;
class PassiveLocationProviderManager extends LocationProviderManager {
@@ -65,17 +63,20 @@
@Override
protected ProviderRequest mergeRegistrations(Collection<Registration> registrations) {
- ProviderRequest.Builder providerRequest = new ProviderRequest.Builder()
- .setIntervalMillis(0);
-
- ArrayList<LocationRequest> requests = new ArrayList<>(registrations.size());
+ boolean locationSettingsIgnored = false;
for (Registration registration : registrations) {
- requests.add(registration.getRequest());
- if (registration.getRequest().isLocationSettingsIgnored()) {
- providerRequest.setLocationSettingsIgnored(true);
- }
+ locationSettingsIgnored |= registration.getRequest().isLocationSettingsIgnored();
}
- return providerRequest.setLocationRequests(requests).build();
+ return new ProviderRequest.Builder()
+ .setIntervalMillis(0)
+ .setLocationSettingsIgnored(locationSettingsIgnored)
+ .build();
+ }
+
+ @Override
+ protected long calculateRequestDelayMillis(long newIntervalMs,
+ Collection<Registration> registrations) {
+ return 0;
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index a830e2f..e782d5e 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -44,7 +44,6 @@
import com.android.server.location.util.UserInfoHelper;
import com.android.server.location.util.UserInfoHelper.UserListener;
-import java.io.PrintWriter;
import java.util.Collection;
import java.util.Objects;
@@ -361,11 +360,11 @@
}
@Override
- protected void dumpServiceState(PrintWriter pw) {
+ protected String getServiceState() {
if (!isServiceSupported()) {
- pw.print("unsupported");
+ return "unsupported";
} else {
- super.dumpServiceState(pw);
+ return super.getServiceState();
}
}
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 87d668a..0318ffb 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -57,6 +57,8 @@
* <li>{@link #onRegister()}</li>
* <li>{@link ListenerRegistration#onRegister(Object)}</li>
* <li>{@link #onRegistrationAdded(Object, ListenerRegistration)}</li>
+ * <li>{@link #onRegistrationReplaced(Object, ListenerRegistration, ListenerRegistration)} (only
+ * invoked if this registration is replacing a prior registration)</li>
* <li>{@link #onActive()}</li>
* <li>{@link ListenerRegistration#onActive()}</li>
* <li>{@link ListenerRegistration#onInactive()}</li>
@@ -183,6 +185,17 @@
protected void onRegistrationAdded(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
+ * Invoked instead of {@link #onRegistrationAdded(Object, ListenerRegistration)} if a
+ * registration is replacing an old registration. The old registration will have already been
+ * unregistered. Invoked while holding the multiplexer's internal lock. The default behavior is
+ * simply to call into {@link #onRegistrationAdded(Object, ListenerRegistration)}.
+ */
+ protected void onRegistrationReplaced(@NonNull TKey key, @NonNull TRegistration oldRegistration,
+ @NonNull TRegistration newRegistration) {
+ onRegistrationAdded(key, newRegistration);
+ }
+
+ /**
* Invoked when a registration is removed. Invoked while holding the multiplexer's internal
* lock.
*/
@@ -227,9 +240,10 @@
boolean wasEmpty = mRegistrations.isEmpty();
+ TRegistration oldRegistration = null;
int index = mRegistrations.indexOfKey(key);
if (index >= 0) {
- removeRegistration(index, false);
+ oldRegistration = removeRegistration(index, false);
mRegistrations.setValueAt(index, registration);
} else {
mRegistrations.put(key, registration);
@@ -239,7 +253,11 @@
onRegister();
}
registration.onRegister(key);
- onRegistrationAdded(key, registration);
+ if (oldRegistration == null) {
+ onRegistrationAdded(key, registration);
+ } else {
+ onRegistrationReplaced(key, oldRegistration, registration);
+ }
onRegistrationActiveChanged(registration);
}
}
@@ -320,7 +338,7 @@
}
@GuardedBy("mRegistrations")
- private void removeRegistration(int index, boolean removeEntry) {
+ private TRegistration removeRegistration(int index, boolean removeEntry) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mRegistrations));
}
@@ -347,6 +365,8 @@
}
}
}
+
+ return registration;
}
/**
@@ -535,7 +555,7 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mRegistrations) {
pw.print("service: ");
- dumpServiceState(pw);
+ pw.print(getServiceState());
pw.println();
if (!mRegistrations.isEmpty()) {
@@ -558,18 +578,17 @@
/**
* May be overridden to provide additional details on service state when dumping the manager
- * state.
+ * state. Invoked while holding the multiplexer's internal lock.
*/
- protected void dumpServiceState(PrintWriter pw) {
+ protected String getServiceState() {
if (mServiceRegistered) {
- pw.print("registered");
if (mMerged != null) {
- pw.print(" [");
- pw.print(mMerged);
- pw.print("]");
+ return mMerged.toString();
+ } else {
+ return "registered";
}
} else {
- pw.print("unregistered");
+ return "unregistered";
}
}
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index e28d73e..5dc4318 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -18,7 +18,9 @@
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
-import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import android.annotation.NonNull;
@@ -78,16 +80,19 @@
synchronized (mSharedLock) {
ProviderState currentState = mCurrentState.get();
switch (currentState.stateEnum) {
- case PROVIDER_STATE_ENABLED: {
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN:
+ case PROVIDER_STATE_ENABLED_CERTAIN: {
// Losing a remote provider is treated as becoming uncertain.
String msg = "handleProviderLost reason=" + reason
+ ", mProviderName=" + mProviderName
+ ", currentState=" + currentState;
debugLog(msg);
- // This is an unusual PROVIDER_STATE_ENABLED state because event == null
+ // This is an unusual PROVIDER_STATE_ENABLED_UNCERTAIN state because
+ // event == null
ProviderState newState = currentState.newState(
- PROVIDER_STATE_ENABLED, null, currentState.currentUserConfiguration,
- msg);
+ PROVIDER_STATE_ENABLED_UNCERTAIN, null,
+ currentState.currentUserConfiguration, msg);
setCurrentState(newState, true);
break;
}
@@ -118,7 +123,9 @@
synchronized (mSharedLock) {
ProviderState currentState = mCurrentState.get();
switch (currentState.stateEnum) {
- case PROVIDER_STATE_ENABLED: {
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
debugLog("handleOnProviderBound mProviderName=" + mProviderName
+ ", currentState=" + currentState + ": Provider is enabled.");
break;
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index bedaeda..d482637 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -24,7 +24,9 @@
import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
-import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import android.annotation.NonNull;
@@ -38,19 +40,25 @@
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
import java.time.Duration;
+import java.util.List;
import java.util.Objects;
/**
- * A real implementation of {@link LocationTimeZoneProviderController} that supports a single
- * {@link LocationTimeZoneProvider}.
+ * A real implementation of {@link LocationTimeZoneProviderController} that supports a primary and a
+ * secondary {@link LocationTimeZoneProvider}.
*
- * TODO(b/152744911): This implementation currently only supports a single ("primary") provider.
- * Support for a secondary provider will be added in a later commit.
+ * <p>The primary is used until it fails or becomes uncertain. The secondary will then be enabled.
+ * The controller will immediately make suggestions based on "certain" {@link
+ * LocationTimeZoneEvent}s, i.e. events that demonstrate the provider is certain what the time zone
+ * is. The controller will not make immediate suggestions based on "uncertain" events, giving
+ * providers time to change their mind. This also gives the secondary provider time to initialize
+ * when the primary becomes uncertain.
*/
class ControllerImpl extends LocationTimeZoneProviderController {
- @NonNull private final LocationTimeZoneProvider mProvider;
- @NonNull private final SingleRunnableQueue mDelayedSuggestionQueue;
+ @NonNull private final LocationTimeZoneProvider mPrimaryProvider;
+
+ @NonNull private final LocationTimeZoneProvider mSecondaryProvider;
@GuardedBy("mSharedLock")
// Non-null after initialize()
@@ -65,12 +73,11 @@
private Callback mCallback;
/**
- * Contains any currently pending suggestion on {@link #mDelayedSuggestionQueue}, if there is
- * one.
+ * Used for scheduling uncertainty timeouts, i.e after a provider has reported uncertainty.
+ * This timeout is not provider-specific: it is started when the controller becomes uncertain
+ * due to events it has received from one or other provider.
*/
- @GuardedBy("mSharedLock")
- @Nullable
- private GeolocationTimeZoneSuggestion mPendingSuggestion;
+ @NonNull private final SingleRunnableQueue mUncertaintyTimeoutQueue;
/** Contains the last suggestion actually made, if there is one. */
@GuardedBy("mSharedLock")
@@ -78,10 +85,12 @@
private GeolocationTimeZoneSuggestion mLastSuggestion;
ControllerImpl(@NonNull ThreadingDomain threadingDomain,
- @NonNull LocationTimeZoneProvider provider) {
+ @NonNull LocationTimeZoneProvider primaryProvider,
+ @NonNull LocationTimeZoneProvider secondaryProvider) {
super(threadingDomain);
- mDelayedSuggestionQueue = threadingDomain.createSingleRunnableQueue();
- mProvider = Objects.requireNonNull(provider);
+ mUncertaintyTimeoutQueue = threadingDomain.createSingleRunnableQueue();
+ mPrimaryProvider = Objects.requireNonNull(primaryProvider);
+ mSecondaryProvider = Objects.requireNonNull(secondaryProvider);
}
@Override
@@ -94,8 +103,13 @@
mCallback = Objects.requireNonNull(callback);
mCurrentUserConfiguration = environment.getCurrentUserConfigurationInternal();
- mProvider.initialize(ControllerImpl.this::onProviderStateChange);
- enableOrDisableProvider(mCurrentUserConfiguration);
+ LocationTimeZoneProvider.ProviderListener providerListener =
+ ControllerImpl.this::onProviderStateChange;
+ mPrimaryProvider.initialize(providerListener);
+ mSecondaryProvider.initialize(providerListener);
+
+ alterProvidersEnabledStateIfRequired(
+ null /* oldConfiguration */, mCurrentUserConfiguration);
}
}
@@ -112,154 +126,281 @@
if (!newConfig.equals(oldConfig)) {
if (newConfig.getUserId() != oldConfig.getUserId()) {
- // If the user changed, disable the provider if needed. It may be re-enabled for
- // the new user below if their settings allow.
+ // If the user changed, disable the providers if needed. They may be re-enabled
+ // for the new user immediately afterwards if their settings allow.
debugLog("User changed. old=" + oldConfig.getUserId()
- + ", new=" + newConfig.getUserId());
- debugLog("Disabling LocationTimeZoneProviders as needed");
- if (mProvider.getCurrentState().stateEnum == PROVIDER_STATE_ENABLED) {
- mProvider.disable();
- }
- }
+ + ", new=" + newConfig.getUserId() + ": Disabling providers");
+ disableProviders();
- enableOrDisableProvider(newConfig);
+ alterProvidersEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
+ } else {
+ alterProvidersEnabledStateIfRequired(oldConfig, newConfig);
+ }
}
}
}
+ @Override
+ boolean isUncertaintyTimeoutSet() {
+ return mUncertaintyTimeoutQueue.hasQueued();
+ }
+
+ @Override
+ long getUncertaintyTimeoutDelayMillis() {
+ return mUncertaintyTimeoutQueue.getQueuedDelayMillis();
+ }
+
@GuardedBy("mSharedLock")
- private void enableOrDisableProvider(@NonNull ConfigurationInternal configuration) {
- ProviderState providerState = mProvider.getCurrentState();
- boolean geoDetectionEnabled = configuration.getGeoDetectionEnabledBehavior();
- boolean providerWasEnabled = providerState.stateEnum == PROVIDER_STATE_ENABLED;
- if (geoDetectionEnabled) {
- switch (providerState.stateEnum) {
- case PROVIDER_STATE_DISABLED: {
- debugLog("Enabling " + mProvider);
- mProvider.enable(
- configuration, mEnvironment.getProviderInitializationTimeout());
- break;
- }
- case PROVIDER_STATE_ENABLED: {
- debugLog("No need to enable " + mProvider + ": already enabled");
- break;
- }
- case PROVIDER_STATE_PERM_FAILED: {
- debugLog("Unable to enable " + mProvider + ": it is perm failed");
- break;
- }
- default:
- warnLog("Unknown provider state: " + mProvider);
- break;
+ private void disableProviders() {
+ disableProviderIfEnabled(mPrimaryProvider);
+ disableProviderIfEnabled(mSecondaryProvider);
+
+ // By definition, if both providers are disabled, the controller is uncertain.
+ cancelUncertaintyTimeout();
+ }
+
+ @GuardedBy("mSharedLock")
+ private void disableProviderIfEnabled(@NonNull LocationTimeZoneProvider provider) {
+ if (provider.getCurrentState().isEnabled()) {
+ disableProvider(provider);
+ }
+ }
+
+ @GuardedBy("mSharedLock")
+ private void disableProvider(@NonNull LocationTimeZoneProvider provider) {
+ ProviderState providerState = provider.getCurrentState();
+ switch (providerState.stateEnum) {
+ case PROVIDER_STATE_DISABLED: {
+ debugLog("No need to disable " + provider + ": already disabled");
+ break;
}
- } else {
- switch (providerState.stateEnum) {
- case PROVIDER_STATE_DISABLED: {
- debugLog("No need to disable " + mProvider + ": already enabled");
- break;
- }
- case PROVIDER_STATE_ENABLED: {
- debugLog("Disabling " + mProvider);
- mProvider.disable();
- break;
- }
- case PROVIDER_STATE_PERM_FAILED: {
- debugLog("Unable to disable " + mProvider + ": it is perm failed");
- break;
- }
- default: {
- warnLog("Unknown provider state: " + mProvider);
- break;
- }
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
+ debugLog("Disabling " + provider);
+ provider.disable();
+ break;
+ }
+ case PROVIDER_STATE_PERM_FAILED: {
+ debugLog("Unable to disable " + provider + ": it is perm failed");
+ break;
+ }
+ default: {
+ warnLog("Unknown provider state: " + provider);
+ break;
}
}
+ }
- boolean isProviderEnabled =
- mProvider.getCurrentState().stateEnum == PROVIDER_STATE_ENABLED;
+ /**
+ * Sets the providers into the correct enabled/disabled state for the {@code newConfiguration}
+ * and, if there is a provider state change, makes any suggestions required to inform the
+ * downstream time zone detection code.
+ *
+ * <p>This is a utility method that exists to avoid duplicated logic for the various cases when
+ * provider enabled / disabled state may need to be set or changed, e.g. during initialization
+ * or when a new configuration has been received.
+ */
+ @GuardedBy("mSharedLock")
+ private void alterProvidersEnabledStateIfRequired(
+ @Nullable ConfigurationInternal oldConfiguration,
+ @NonNull ConfigurationInternal newConfiguration) {
- if (isProviderEnabled) {
- if (!providerWasEnabled) {
- // When a provider has first been enabled, we allow it some time for it to
- // initialize before sending its first event.
- Duration initializationTimeout = mEnvironment.getProviderInitializationTimeout()
- .plus(mEnvironment.getProviderInitializationTimeoutFuzz());
- // This sets up an empty suggestion to trigger if no explicit "certain" or
- // "uncertain" suggestion preempts it within initializationTimeout. If, for some
- // reason, the provider does not produce any events then this scheduled suggestion
- // will ensure the controller makes at least an "uncertain" suggestion.
- suggestDelayed(createEmptySuggestion("No event received from provider in"
- + " initializationTimeout=" + initializationTimeout),
- initializationTimeout);
+ // Provider enabled / disabled states only need to be changed if geoDetectionEnabled has
+ // changed.
+ boolean oldGeoDetectionEnabled = oldConfiguration != null
+ && oldConfiguration.getGeoDetectionEnabledBehavior();
+ boolean newGeoDetectionEnabled = newConfiguration.getGeoDetectionEnabledBehavior();
+ if (oldGeoDetectionEnabled == newGeoDetectionEnabled) {
+ return;
+ }
+
+ // The check above ensures that the logic below only executes if providers are going from
+ // {enabled *} -> {disabled}, or {disabled} -> {enabled initializing}. If this changes in
+ // future and there could be {enabled *} -> {enabled *} cases, or cases where the provider
+ // can't be assumed to go straight to the {enabled initializing} state, then the logic below
+ // would need to cover extra conditions, for example:
+ // 1) If the primary is in {enabled uncertain}, the secondary should be enabled.
+ // 2) If (1), and the secondary instantly enters the {perm failed} state, the uncertainty
+ // timeout started when the primary entered {enabled uncertain} should be cancelled.
+
+ if (newGeoDetectionEnabled) {
+ // Try to enable the primary provider.
+ tryEnableProvider(mPrimaryProvider, newConfiguration);
+
+ // The secondary should only ever be enabled if the primary now isn't enabled (i.e. it
+ // couldn't become {enabled initializing} because it is {perm failed}).
+ ProviderState newPrimaryState = mPrimaryProvider.getCurrentState();
+ if (!newPrimaryState.isEnabled()) {
+ // If the primary provider is {perm failed} then the controller must try to enable
+ // the secondary.
+ tryEnableProvider(mSecondaryProvider, newConfiguration);
+
+ ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
+ if (!newSecondaryState.isEnabled()) {
+ // If both providers are {perm failed} then the controller immediately
+ // becomes uncertain.
+ GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+ "Providers are failed:"
+ + " primary=" + mPrimaryProvider.getCurrentState()
+ + " secondary=" + mPrimaryProvider.getCurrentState());
+ makeSuggestion(suggestion);
+ }
}
} else {
- // Clear any queued suggestions.
- clearDelayedSuggestion();
+ disableProviders();
- // If the provider is now not enabled, and a previous "certain" suggestion has been
- // made, then a new "uncertain" suggestion must be made to indicate the provider no
- // longer has an opinion and will not be sending updates.
+ // There can be an uncertainty timeout set if the controller most recently received
+ // an uncertain event. This is a no-op if there isn't a timeout set.
+ cancelUncertaintyTimeout();
+
+ // If a previous "certain" suggestion has been made, then a new "uncertain"
+ // suggestion must now be made to indicate the controller {does not / no longer has}
+ // an opinion and will not be sending further updates (until at least the config
+ // changes again and providers are re-enabled).
if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
- suggestImmediate(createEmptySuggestion(
- "Provider disabled, clearing previous suggestion"));
+ GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+ "Provider is disabled:"
+ + " primary=" + mPrimaryProvider.getCurrentState());
+ makeSuggestion(suggestion);
+ }
+ }
+ }
+
+ private void tryEnableProvider(@NonNull LocationTimeZoneProvider provider,
+ @NonNull ConfigurationInternal configuration) {
+ ProviderState providerState = provider.getCurrentState();
+ switch (providerState.stateEnum) {
+ case PROVIDER_STATE_DISABLED: {
+ debugLog("Enabling " + provider);
+ provider.enable(configuration, mEnvironment.getProviderInitializationTimeout(),
+ mEnvironment.getProviderInitializationTimeoutFuzz());
+ break;
+ }
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
+ debugLog("No need to enable " + provider + ": already enabled");
+ break;
+ }
+ case PROVIDER_STATE_PERM_FAILED: {
+ debugLog("Unable to enable " + provider + ": it is perm failed");
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unknown provider state:"
+ + " provider=" + provider);
}
}
}
void onProviderStateChange(@NonNull ProviderState providerState) {
mThreadingDomain.assertCurrentThread();
- assertProviderKnown(providerState.provider);
+ LocationTimeZoneProvider provider = providerState.provider;
+ assertProviderKnown(provider);
synchronized (mSharedLock) {
switch (providerState.stateEnum) {
case PROVIDER_STATE_DISABLED: {
- // This should never happen: entering disabled does not trigger an event.
+ // This should never happen: entering disabled does not trigger a state change.
warnLog("onProviderStateChange: Unexpected state change for disabled provider,"
- + " providerState=" + providerState);
+ + " provider=" + provider);
break;
}
- case PROVIDER_STATE_ENABLED: {
- // Entering enabled does not trigger an event, so this only happens if an event
- // is received while the provider is enabled.
- debugLog("onProviderStateChange: Received notification of an event while"
- + " enabled, providerState=" + providerState);
- providerEnabledProcessEvent(providerState);
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
+ // Entering enabled does not trigger a state change, so this only happens if an
+ // event is received while the provider is enabled.
+ debugLog("onProviderStateChange: Received notification of a state change while"
+ + " enabled, provider=" + provider);
+ handleProviderEnabledStateChange(providerState);
break;
}
case PROVIDER_STATE_PERM_FAILED: {
debugLog("Received notification of permanent failure for"
- + " provider=" + providerState);
- GeolocationTimeZoneSuggestion suggestion = createEmptySuggestion(
- "provider=" + providerState.provider
- + " permanently failed: " + providerState);
- suggestImmediate(suggestion);
+ + " provider=" + provider);
+ handleProviderFailedStateChange(providerState);
break;
}
default: {
- warnLog("onProviderStateChange: Unexpected providerState=" + providerState);
+ warnLog("onProviderStateChange: Unexpected provider=" + provider);
}
}
}
}
- private void assertProviderKnown(LocationTimeZoneProvider provider) {
- if (provider != mProvider) {
+ private void assertProviderKnown(@NonNull LocationTimeZoneProvider provider) {
+ if (provider != mPrimaryProvider && provider != mSecondaryProvider) {
throw new IllegalArgumentException("Unknown provider: " + provider);
}
}
/**
- * Called when a provider has changed state but just moved from a PROVIDER_STATE_ENABLED state
- * to another PROVIDER_STATE_ENABLED state, usually as a result of a new {@link
- * LocationTimeZoneEvent} being received. There are some cases where event can be null.
+ * Called when a provider has reported that it has failed permanently.
*/
- private void providerEnabledProcessEvent(@NonNull ProviderState providerState) {
+ @GuardedBy("mSharedLock")
+ private void handleProviderFailedStateChange(@NonNull ProviderState providerState) {
+ LocationTimeZoneProvider failedProvider = providerState.provider;
+ ProviderState primaryCurrentState = mPrimaryProvider.getCurrentState();
+ ProviderState secondaryCurrentState = mSecondaryProvider.getCurrentState();
+
+ // If a provider has failed, the other may need to be enabled.
+ if (failedProvider == mPrimaryProvider) {
+ if (secondaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
+ // The primary must have failed. Try to enable the secondary. This does nothing if
+ // the provider is already enabled, and will leave the provider in
+ // {enabled initializing} if the provider is disabled.
+ tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
+ }
+ } else if (failedProvider == mSecondaryProvider) {
+ // No-op: The secondary will only be active if the primary is uncertain or is failed.
+ // So, there the primary should not need to be enabled when the secondary fails.
+ if (primaryCurrentState.stateEnum != PROVIDER_STATE_ENABLED_UNCERTAIN
+ && primaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
+ warnLog("Secondary provider unexpected reported a failure:"
+ + " failed provider=" + failedProvider.getName()
+ + ", primary provider=" + mPrimaryProvider
+ + ", secondary provider=" + mSecondaryProvider);
+ }
+ }
+
+ // If both providers are now failed, the controller needs to tell the next component in the
+ // time zone detection process.
+ if (primaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED
+ && secondaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED) {
+
+ // If both providers are newly failed then the controller is uncertain by definition
+ // and it will never recover so it can send a suggestion immediately.
+ cancelUncertaintyTimeout();
+
+ // If both providers are now failed, then a suggestion must be sent informing the time
+ // zone detector that there are no further updates coming in future.
+ GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+ "Both providers are permanently failed:"
+ + " primary=" + primaryCurrentState.provider
+ + ", secondary=" + secondaryCurrentState.provider);
+ makeSuggestion(suggestion);
+ }
+ }
+
+ /**
+ * Called when a provider has changed state but just moved from one enabled state to another
+ * enabled state, usually as a result of a new {@link LocationTimeZoneEvent} being received.
+ * However, there are rare cases where the event can also be null.
+ */
+ @GuardedBy("mSharedLock")
+ private void handleProviderEnabledStateChange(@NonNull ProviderState providerState) {
+ LocationTimeZoneProvider provider = providerState.provider;
LocationTimeZoneEvent event = providerState.event;
if (event == null) {
// Implicit uncertainty, i.e. where the provider is enabled, but a problem has been
// detected without having received an event. For example, if the process has detected
- // the loss of a binder-based provider. This is treated like explicit uncertainty, i.e.
- // where the provider has explicitly told this process it is uncertain.
- scheduleUncertainSuggestionIfNeeded(null);
+ // the loss of a binder-based provider, or initialization took too long. This is treated
+ // the same as explicit uncertainty, i.e. where the provider has explicitly told this
+ // process it is uncertain.
+ handleProviderUncertainty(provider, "provider=" + provider
+ + ", implicit uncertainty, event=null");
return;
}
@@ -273,28 +414,26 @@
if (!mCurrentUserConfiguration.getGeoDetectionEnabledBehavior()) {
// This should not happen: the provider should not be in an enabled state if the user
// does not have geodetection enabled.
- warnLog("Provider=" + providerState + " is enabled, but currentUserConfiguration="
- + mCurrentUserConfiguration + " suggests it shouldn't be.");
+ warnLog("Provider=" + provider + " is enabled, but"
+ + " currentUserConfiguration=" + mCurrentUserConfiguration
+ + " suggests it shouldn't be.");
}
switch (event.getEventType()) {
case EVENT_TYPE_PERMANENT_FAILURE: {
- // This shouldn't happen. Providers cannot be enabled and have this event.
- warnLog("Provider=" + providerState
+ // This shouldn't happen. A provider cannot be enabled and have this event type.
+ warnLog("Provider=" + provider
+ " is enabled, but event suggests it shouldn't be");
break;
}
case EVENT_TYPE_UNCERTAIN: {
- scheduleUncertainSuggestionIfNeeded(event);
+ handleProviderUncertainty(provider, "provider=" + provider
+ + ", explicit uncertainty. event=" + event);
break;
}
case EVENT_TYPE_SUCCESS: {
- GeolocationTimeZoneSuggestion suggestion =
- new GeolocationTimeZoneSuggestion(event.getTimeZoneIds());
- suggestion.addDebugInfo("Event received provider=" + mProvider.getName()
- + ", event=" + event);
- // Rely on the receiver to dedupe events. It is better to over-communicate.
- suggestImmediate(suggestion);
+ handleProviderCertainty(provider, event.getTimeZoneIds(),
+ "Event received provider=" + provider + ", event=" + event);
break;
}
default: {
@@ -305,29 +444,25 @@
}
/**
- * Indicates a provider has become uncertain with the event (if any) received that indicates
- * that.
- *
- * <p>Providers are expected to report their uncertainty as soon as they become uncertain, as
- * this enables the most flexibility for the controller to enable other providers when there are
- * multiple ones available. The controller is therefore responsible for deciding when to make a
- * "uncertain" suggestion.
- *
- * <p>This method schedules an "uncertain" suggestion (if one isn't already scheduled) to be
- * made later if nothing else preempts it. It can be preempted if the provider becomes certain
- * (or does anything else that calls {@link #suggestImmediate(GeolocationTimeZoneSuggestion)})
- * within {@link Environment#getUncertaintyDelay()}. Preemption causes the scheduled
- * "uncertain" event to be cancelled. If the provider repeatedly sends uncertainty events within
- * the uncertainty delay period, those events are effectively ignored (i.e. the timer is not
- * reset each time).
+ * Called when a provider has become "certain" about the time zone(s).
*/
- private void scheduleUncertainSuggestionIfNeeded(@Nullable LocationTimeZoneEvent event) {
- if (mPendingSuggestion == null || mPendingSuggestion.getZoneIds() != null) {
- GeolocationTimeZoneSuggestion suggestion = createEmptySuggestion(
- "provider=" + mProvider + " became uncertain, event=" + event);
- // Only send the empty suggestion after the uncertainty delay.
- suggestDelayed(suggestion, mEnvironment.getUncertaintyDelay());
+ @GuardedBy("mSharedLock")
+ private void handleProviderCertainty(
+ @NonNull LocationTimeZoneProvider provider,
+ @Nullable List<String> timeZoneIds,
+ @NonNull String reason) {
+ // By definition, the controller is now certain.
+ cancelUncertaintyTimeout();
+
+ if (provider == mPrimaryProvider) {
+ disableProviderIfEnabled(mSecondaryProvider);
}
+
+ GeolocationTimeZoneSuggestion suggestion =
+ new GeolocationTimeZoneSuggestion(timeZoneIds);
+ suggestion.addDebugInfo(reason);
+ // Rely on the receiver to dedupe suggestions. It is better to over-communicate.
+ makeSuggestion(suggestion);
}
@Override
@@ -342,66 +477,90 @@
ipw.println("providerInitializationTimeoutFuzz="
+ mEnvironment.getProviderInitializationTimeoutFuzz());
ipw.println("uncertaintyDelay=" + mEnvironment.getUncertaintyDelay());
- ipw.println("mPendingSuggestion=" + mPendingSuggestion);
ipw.println("mLastSuggestion=" + mLastSuggestion);
- ipw.println("Provider:");
+ ipw.println("Primary Provider:");
ipw.increaseIndent(); // level 2
- mProvider.dump(ipw, args);
+ mPrimaryProvider.dump(ipw, args);
+ ipw.decreaseIndent(); // level 2
+
+ ipw.println("Secondary Provider:");
+ ipw.increaseIndent(); // level 2
+ mSecondaryProvider.dump(ipw, args);
ipw.decreaseIndent(); // level 2
ipw.decreaseIndent(); // level 1
}
}
- /** Sends an immediate suggestion, cancelling any pending suggestion. */
+ /** Sends an immediate suggestion, updating mLastSuggestion. */
@GuardedBy("mSharedLock")
- private void suggestImmediate(@NonNull GeolocationTimeZoneSuggestion suggestion) {
- debugLog("suggestImmediate: Executing suggestion=" + suggestion);
- mDelayedSuggestionQueue.runSynchronously(() -> mCallback.suggest(suggestion));
- mPendingSuggestion = null;
+ private void makeSuggestion(@NonNull GeolocationTimeZoneSuggestion suggestion) {
+ debugLog("makeSuggestion: suggestion=" + suggestion);
+ mCallback.suggest(suggestion);
mLastSuggestion = suggestion;
}
- /** Clears any pending suggestion. */
+ /** Clears the uncertainty timeout. */
@GuardedBy("mSharedLock")
- private void clearDelayedSuggestion() {
- mDelayedSuggestionQueue.cancel();
- mPendingSuggestion = null;
+ private void cancelUncertaintyTimeout() {
+ mUncertaintyTimeoutQueue.cancel();
}
-
/**
- * Schedules a delayed suggestion. There can only be one delayed suggestion at a time.
- * If there is a pending scheduled suggestion equal to the one passed, it will not be replaced.
- * Replacing a previous delayed suggestion has the effect of cancelling the timeout associated
- * with that previous suggestion.
+ * Called when a provider has become "uncertain" about the time zone.
+ *
+ * <p>A provider is expected to report its uncertainty as soon as it becomes uncertain, as
+ * this enables the most flexibility for the controller to enable other providers when there are
+ * multiple ones available. The controller is therefore responsible for deciding when to make a
+ * "uncertain" suggestion to the downstream time zone detector.
+ *
+ * <p>This method schedules an "uncertainty" timeout (if one isn't already scheduled) to be
+ * triggered later if nothing else preempts it. It can be preempted if the provider becomes
+ * certain (or does anything else that calls {@link
+ * #makeSuggestion(GeolocationTimeZoneSuggestion)}) within {@link
+ * Environment#getUncertaintyDelay()}. Preemption causes the scheduled
+ * "uncertainty" timeout to be cancelled. If the provider repeatedly sends uncertainty events
+ * within the uncertainty delay period, those events are effectively ignored (i.e. the timeout
+ * is not reset each time).
*/
@GuardedBy("mSharedLock")
- private void suggestDelayed(@NonNull GeolocationTimeZoneSuggestion suggestion,
- @NonNull Duration delay) {
- Objects.requireNonNull(suggestion);
- Objects.requireNonNull(delay);
+ void handleProviderUncertainty(
+ @NonNull LocationTimeZoneProvider provider, @NonNull String reason) {
+ Objects.requireNonNull(provider);
- if (Objects.equals(mPendingSuggestion, suggestion)) {
- // Do not reset the timer.
- debugLog("suggestDelayed: Suggestion=" + suggestion + " is equal to existing."
- + " Not scheduled.");
- return;
+ // Start the uncertainty timeout if needed to ensure the controller will eventually make an
+ // uncertain suggestion if no success event arrives in time to counteract it.
+ if (!mUncertaintyTimeoutQueue.hasQueued()) {
+ debugLog("Starting uncertainty timeout: reason=" + reason);
+
+ Duration delay = mEnvironment.getUncertaintyDelay();
+ mUncertaintyTimeoutQueue.runDelayed(() -> onProviderUncertaintyTimeout(provider),
+ delay.toMillis());
}
- debugLog("suggestDelayed: Scheduling suggestion=" + suggestion);
- mPendingSuggestion = suggestion;
-
- mDelayedSuggestionQueue.runDelayed(() -> {
- debugLog("suggestDelayed: Executing suggestion=" + suggestion);
- mCallback.suggest(suggestion);
- mPendingSuggestion = null;
- mLastSuggestion = suggestion;
- }, delay.toMillis());
+ if (provider == mPrimaryProvider) {
+ // (Try to) enable the secondary. It could already be enabled, or enabling might not
+ // succeed if the provider has previously reported it is perm failed. The uncertainty
+ // timeout (set above) is used to ensure that an uncertain suggestion will be made if
+ // the secondary cannot generate a success event in time.
+ tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
+ }
}
- private static GeolocationTimeZoneSuggestion createEmptySuggestion(String reason) {
+ private void onProviderUncertaintyTimeout(@NonNull LocationTimeZoneProvider provider) {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+ "Uncertainty timeout triggered for " + provider.getName() + ":"
+ + " primary=" + mPrimaryProvider
+ + ", secondary=" + mSecondaryProvider);
+ makeSuggestion(suggestion);
+ }
+ }
+
+ private static GeolocationTimeZoneSuggestion createUncertainSuggestion(@NonNull String reason) {
GeolocationTimeZoneSuggestion suggestion = new GeolocationTimeZoneSuggestion(null);
suggestion.addDebugInfo(reason);
return suggestion;
@@ -411,18 +570,25 @@
* Asynchronously passes a {@link SimulatedBinderProviderEvent] to the appropriate provider.
* If the provider name does not match a known provider, then the event is logged and discarded.
*/
- void simulateBinderProviderEvent(SimulatedBinderProviderEvent event) {
- if (!Objects.equals(mProvider.getName(), event.getProviderName())) {
+ void simulateBinderProviderEvent(@NonNull SimulatedBinderProviderEvent event) {
+ String targetProviderName = event.getProviderName();
+ LocationTimeZoneProvider targetProvider;
+ if (Objects.equals(mPrimaryProvider.getName(), targetProviderName)) {
+ targetProvider = mPrimaryProvider;
+ } else if (Objects.equals(mSecondaryProvider.getName(), targetProviderName)) {
+ targetProvider = mSecondaryProvider;
+ } else {
warnLog("Unable to process simulated binder provider event,"
+ " unknown providerName in event=" + event);
return;
}
- if (!(mProvider instanceof BinderLocationTimeZoneProvider)) {
+ if (!(targetProvider instanceof BinderLocationTimeZoneProvider)) {
warnLog("Unable to process simulated binder provider event,"
- + " provider is not a " + BinderLocationTimeZoneProvider.class
+ + " provider=" + targetProvider
+ + " is not a " + BinderLocationTimeZoneProvider.class
+ ", event=" + event);
return;
}
- ((BinderLocationTimeZoneProvider) mProvider).simulateBinderProviderEvent(event);
+ ((BinderLocationTimeZoneProvider) targetProvider).simulateBinderProviderEvent(event);
}
}
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index 238f999..a8589d4 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -44,8 +44,8 @@
* are made to the {@link TimeZoneDetectorInternal}, and the {@link LocationTimeZoneProvider}s that
* offer {@link android.location.timezone.LocationTimeZoneEvent}s.
*
- * TODO(b/152744911): This implementation currently only supports a primary provider. Support for a
- * secondary provider must be added in a later commit.
+ * <p>For details of the time zone suggestion behavior, see {@link
+ * LocationTimeZoneProviderController}.
*
* <p>Implementation details:
*
@@ -109,6 +109,7 @@
static final String TAG = "LocationTZDetector";
static final String PRIMARY_PROVIDER_NAME = "primary";
+ static final String SECONDARY_PROVIDER_NAME = "secondary";
private static final String SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX =
"persist.sys.location_tz_simulation_mode.";
@@ -117,6 +118,8 @@
private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
"com.android.location.timezone.service.v1.PrimaryLocationTimeZoneProvider";
+ private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
+ "com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider";
@NonNull private final Context mContext;
@@ -160,7 +163,9 @@
// Called on an arbitrary thread during initialization.
synchronized (mSharedLock) {
LocationTimeZoneProvider primary = createPrimaryProvider();
- mLocationTimeZoneDetectorController = new ControllerImpl(mThreadingDomain, primary);
+ LocationTimeZoneProvider secondary = createSecondaryProvider();
+ mLocationTimeZoneDetectorController =
+ new ControllerImpl(mThreadingDomain, primary, secondary);
ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl(
mThreadingDomain, mLocationTimeZoneDetectorController);
@@ -177,9 +182,6 @@
if (isInSimulationMode(PRIMARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
- // TODO Uncomment this code in a later commit.
- throw new UnsupportedOperationException("Not implemented");
- /*
proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
mContext,
mThreadingDomain,
@@ -187,11 +189,31 @@
com.android.internal.R.bool.config_enablePrimaryLocationTimeZoneOverlay,
com.android.internal.R.string.config_primaryLocationTimeZoneProviderPackageName
);
- */
}
return createLocationTimeZoneProvider(PRIMARY_PROVIDER_NAME, proxy);
}
+ private LocationTimeZoneProvider createSecondaryProvider() {
+ LocationTimeZoneProviderProxy proxy;
+ if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
+ proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+ } else {
+ // TODO Uncomment this code in a later commit.
+ throw new UnsupportedOperationException("Not implemented");
+ /*
+ proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+ mContext,
+ mThreadingDomain,
+ SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
+ com.android.internal.R.bool.config_enableSecondaryLocationTimeZoneOverlay,
+ com.android.internal.R.string
+ .config_secondaryLocationTimeZoneProviderPackageName
+ );
+ */
+ }
+ return createLocationTimeZoneProvider(SECONDARY_PROVIDER_NAME, proxy);
+ }
+
private boolean isInSimulationMode(String providerName) {
return SystemProperties.getBoolean(
SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX + providerName, false);
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
index abfa580..4bbda43 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
@@ -22,7 +22,9 @@
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
-import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import android.annotation.IntDef;
@@ -33,6 +35,9 @@
import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue;
import com.android.server.timezonedetector.ConfigurationInternal;
import com.android.server.timezonedetector.Dumpable;
import com.android.server.timezonedetector.ReferenceWithHistory;
@@ -73,8 +78,9 @@
*/
static class ProviderState {
- @IntDef({ PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_ENABLED, PROVIDER_STATE_DISABLED,
- PROVIDER_STATE_PERM_FAILED })
+ @IntDef({ PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_ENABLED_INITIALIZING,
+ PROVIDER_STATE_ENABLED_CERTAIN, PROVIDER_STATE_ENABLED_UNCERTAIN,
+ PROVIDER_STATE_DISABLED, PROVIDER_STATE_PERM_FAILED })
@interface ProviderStateEnum {}
/**
@@ -83,22 +89,33 @@
static final int PROVIDER_STATE_UNKNOWN = 0;
/**
- * The provider is currently enabled.
+ * The provider is enabled and has not reported its first event.
*/
- static final int PROVIDER_STATE_ENABLED = 1;
+ static final int PROVIDER_STATE_ENABLED_INITIALIZING = 1;
/**
- * The provider is currently disabled.
+ * The provider is enabled and most recently reported a "success" event.
+ */
+ static final int PROVIDER_STATE_ENABLED_CERTAIN = 2;
+
+ /**
+ * The provider is enabled and most recently reported an "uncertain" event.
+ */
+ static final int PROVIDER_STATE_ENABLED_UNCERTAIN = 3;
+
+ /**
+ * The provider is disabled.
+ *
* This is the state after {@link #initialize} is called.
*/
- static final int PROVIDER_STATE_DISABLED = 2;
+ static final int PROVIDER_STATE_DISABLED = 4;
/**
* The provider has failed and cannot be re-enabled.
*
* Providers may enter this state after a provider is enabled.
*/
- static final int PROVIDER_STATE_PERM_FAILED = 3;
+ static final int PROVIDER_STATE_PERM_FAILED = 5;
/** The {@link LocationTimeZoneProvider} the state is for. */
public final @NonNull LocationTimeZoneProvider provider;
@@ -108,14 +125,15 @@
/**
* The last {@link LocationTimeZoneEvent} received. Only populated when {@link #stateEnum}
- * is {@link #PROVIDER_STATE_ENABLED}, but it can be {@code null} then too if no event has
+ * is either {@link #PROVIDER_STATE_ENABLED_CERTAIN} or {@link
+ * #PROVIDER_STATE_ENABLED_UNCERTAIN}, but it can be {@code null} then too if no event has
* yet been received.
*/
@Nullable public final LocationTimeZoneEvent event;
/**
* The user configuration associated with the current state. Only and always present when
- * {@link #stateEnum} is {@link #PROVIDER_STATE_ENABLED}.
+ * {@link #stateEnum} is one of the enabled states.
*/
@Nullable public final ConfigurationInternal currentUserConfiguration;
@@ -133,7 +151,8 @@
private ProviderState(@NonNull LocationTimeZoneProvider provider,
- @ProviderStateEnum int stateEnum, @Nullable LocationTimeZoneEvent event,
+ @ProviderStateEnum int stateEnum,
+ @Nullable LocationTimeZoneEvent event,
@Nullable ConfigurationInternal currentUserConfiguration,
@Nullable String debugInfo) {
this.provider = Objects.requireNonNull(provider);
@@ -172,7 +191,9 @@
break;
}
case PROVIDER_STATE_DISABLED:
- case PROVIDER_STATE_ENABLED: {
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
// These can go to each other or PROVIDER_STATE_PERM_FAILED.
break;
}
@@ -200,7 +221,9 @@
}
break;
}
- case PROVIDER_STATE_ENABLED: {
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
if (currentUserConfig == null) {
throw new IllegalArgumentException(
"Enabled state: currentUserConfig must not be null");
@@ -223,9 +246,18 @@
return new ProviderState(provider, newStateEnum, event, currentUserConfig, debugInfo);
}
+ /** Returns {@code true} if {@link #stateEnum} is one of the enabled states. */
+ boolean isEnabled() {
+ return stateEnum == PROVIDER_STATE_ENABLED_INITIALIZING
+ || stateEnum == PROVIDER_STATE_ENABLED_CERTAIN
+ || stateEnum == PROVIDER_STATE_ENABLED_UNCERTAIN;
+ }
+
@Override
public String toString() {
- return "State{"
+ // this.provider is omitted deliberately to avoid recursion, since the provider holds
+ // a reference to its state.
+ return "ProviderState{"
+ "stateEnum=" + prettyPrintStateEnum(stateEnum)
+ ", event=" + event
+ ", currentUserConfiguration=" + currentUserConfiguration
@@ -257,8 +289,12 @@
switch (state) {
case PROVIDER_STATE_DISABLED:
return "Disabled (" + PROVIDER_STATE_DISABLED + ")";
- case PROVIDER_STATE_ENABLED:
- return "Enabled (" + PROVIDER_STATE_ENABLED + ")";
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ return "Enabled initializing (" + PROVIDER_STATE_ENABLED_INITIALIZING + ")";
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ return "Enabled certain (" + PROVIDER_STATE_ENABLED_CERTAIN + ")";
+ case PROVIDER_STATE_ENABLED_UNCERTAIN:
+ return "Enabled uncertain (" + PROVIDER_STATE_ENABLED_UNCERTAIN + ")";
case PROVIDER_STATE_PERM_FAILED:
return "Perm failure (" + PROVIDER_STATE_PERM_FAILED + ")";
case PROVIDER_STATE_UNKNOWN:
@@ -279,6 +315,11 @@
final ReferenceWithHistory<ProviderState> mCurrentState =
new ReferenceWithHistory<>(10);
+ /**
+ * Used for scheduling initialization timeouts, i.e. for providers that have just been enabled.
+ */
+ @NonNull private final SingleRunnableQueue mInitializationTimeoutQueue;
+
// Non-null and effectively final after initialize() is called.
ProviderListener mProviderListener;
@@ -286,6 +327,7 @@
LocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain,
@NonNull String providerName) {
mThreadingDomain = Objects.requireNonNull(threadingDomain);
+ mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue();
mSharedLock = threadingDomain.getLockObject();
mProviderName = Objects.requireNonNull(providerName);
}
@@ -303,7 +345,8 @@
mProviderListener = Objects.requireNonNull(providerListener);
ProviderState currentState = ProviderState.createStartingState(this);
ProviderState newState = currentState.newState(
- PROVIDER_STATE_DISABLED, null, null, "initialize() called");
+ PROVIDER_STATE_DISABLED, null, null,
+ "initialize() called");
setCurrentState(newState, false);
onInitialize();
@@ -370,20 +413,41 @@
* called using the handler thread from the {@link ThreadingDomain}.
*/
final void enable(@NonNull ConfigurationInternal currentUserConfiguration,
- @NonNull Duration initializationTimeout) {
+ @NonNull Duration initializationTimeout, @NonNull Duration initializationTimeoutFuzz) {
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
assertCurrentState(PROVIDER_STATE_DISABLED);
- ProviderState currentState = getCurrentState();
+ ProviderState currentState = mCurrentState.get();
ProviderState newState = currentState.newState(
- PROVIDER_STATE_ENABLED, null, currentUserConfiguration, "enable() called");
+ PROVIDER_STATE_ENABLED_INITIALIZING, null /* event */,
+ currentUserConfiguration, "enable() called");
setCurrentState(newState, false);
+
+ Duration delay = initializationTimeout.plus(initializationTimeoutFuzz);
+ mInitializationTimeoutQueue.runDelayed(
+ this::handleInitializationTimeout, delay.toMillis());
+
onEnable(initializationTimeout);
}
}
+ private void handleInitializationTimeout() {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ ProviderState currentState = mCurrentState.get();
+ if (currentState.stateEnum == PROVIDER_STATE_ENABLED_INITIALIZING) {
+ // On initialization timeout the provider becomes uncertain.
+ ProviderState newState = currentState.newState(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, null /* event */,
+ currentState.currentUserConfiguration, "initialization timeout");
+ setCurrentState(newState, true);
+ }
+ }
+ }
+
/**
* Implemented by subclasses to do work during {@link #enable}.
*/
@@ -391,20 +455,24 @@
/**
* Disables the provider. It is an error* to call this method except when the {@link
- * #getCurrentState()} is at {@link ProviderState#PROVIDER_STATE_ENABLED}. This method must be
+ * #getCurrentState()} is one of the enabled states. This method must be
* called using the handler thread from the {@link ThreadingDomain}.
*/
final void disable() {
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
- assertCurrentState(PROVIDER_STATE_ENABLED);
+ assertIsEnabled();
- ProviderState currentState = getCurrentState();
- ProviderState newState =
- currentState.newState(PROVIDER_STATE_DISABLED, null, null, "disable() called");
+ ProviderState currentState = mCurrentState.get();
+ ProviderState newState = currentState.newState(
+ PROVIDER_STATE_DISABLED, null, null, "disable() called");
setCurrentState(newState, false);
+ if (mInitializationTimeoutQueue.hasQueued()) {
+ mInitializationTimeoutQueue.cancel();
+ }
+
onDisable();
}
}
@@ -424,7 +492,7 @@
debugLog("handleLocationTimeZoneEvent: mProviderName=" + mProviderName
+ ", locationTimeZoneEvent=" + locationTimeZoneEvent);
- ProviderState currentState = getCurrentState();
+ ProviderState currentState = mCurrentState.get();
int eventType = locationTimeZoneEvent.getEventType();
switch (currentState.stateEnum) {
case PROVIDER_STATE_PERM_FAILED: {
@@ -445,6 +513,9 @@
ProviderState newState = currentState.newState(
PROVIDER_STATE_PERM_FAILED, null, null, msg);
setCurrentState(newState, true);
+ if (mInitializationTimeoutQueue.hasQueued()) {
+ mInitializationTimeoutQueue.cancel();
+ }
return;
}
case EVENT_TYPE_SUCCESS:
@@ -464,7 +535,9 @@
}
}
}
- case PROVIDER_STATE_ENABLED: {
+ case PROVIDER_STATE_ENABLED_INITIALIZING:
+ case PROVIDER_STATE_ENABLED_CERTAIN:
+ case PROVIDER_STATE_ENABLED_UNCERTAIN: {
switch (eventType) {
case EVENT_TYPE_PERMANENT_FAILURE: {
String msg = "handleLocationTimeZoneEvent:"
@@ -475,14 +548,27 @@
ProviderState newState = currentState.newState(
PROVIDER_STATE_PERM_FAILED, null, null, msg);
setCurrentState(newState, true);
+ if (mInitializationTimeoutQueue.hasQueued()) {
+ mInitializationTimeoutQueue.cancel();
+ }
+
return;
}
case EVENT_TYPE_UNCERTAIN:
case EVENT_TYPE_SUCCESS: {
- ProviderState newState = currentState.newState(PROVIDER_STATE_ENABLED,
+ @ProviderStateEnum int providerStateEnum;
+ if (eventType == EVENT_TYPE_UNCERTAIN) {
+ providerStateEnum = PROVIDER_STATE_ENABLED_UNCERTAIN;
+ } else {
+ providerStateEnum = PROVIDER_STATE_ENABLED_CERTAIN;
+ }
+ ProviderState newState = currentState.newState(providerStateEnum,
locationTimeZoneEvent, currentState.currentUserConfiguration,
"handleLocationTimeZoneEvent() when enabled");
setCurrentState(newState, true);
+ if (mInitializationTimeoutQueue.hasQueued()) {
+ mInitializationTimeoutQueue.cancel();
+ }
return;
}
default: {
@@ -503,11 +589,34 @@
*/
abstract void logWarn(String msg);
- private void assertCurrentState(@ProviderState.ProviderStateEnum int requiredState) {
- ProviderState currentState = getCurrentState();
+ @GuardedBy("mSharedLock")
+ private void assertIsEnabled() {
+ ProviderState currentState = mCurrentState.get();
+ if (!currentState.isEnabled()) {
+ throw new IllegalStateException("Required an enabled state, but was " + currentState);
+ }
+ }
+
+ @GuardedBy("mSharedLock")
+ private void assertCurrentState(@ProviderStateEnum int requiredState) {
+ ProviderState currentState = mCurrentState.get();
if (currentState.stateEnum != requiredState) {
throw new IllegalStateException(
"Required stateEnum=" + requiredState + ", but was " + currentState);
}
}
+
+ @VisibleForTesting
+ boolean isInitializationTimeoutSet() {
+ synchronized (mSharedLock) {
+ return mInitializationTimeoutQueue.hasQueued();
+ }
+ }
+
+ @VisibleForTesting
+ Duration getInitializationTimeoutDelay() {
+ synchronized (mSharedLock) {
+ return Duration.ofMillis(mInitializationTimeoutQueue.getQueuedDelayMillis());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java
index 88f0f00..ace066e 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.Handler;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState;
import com.android.server.timezonedetector.ConfigurationInternal;
import com.android.server.timezonedetector.Dumpable;
@@ -85,6 +86,12 @@
*/
abstract void onConfigChanged();
+ @VisibleForTesting
+ abstract boolean isUncertaintyTimeoutSet();
+
+ @VisibleForTesting
+ abstract long getUncertaintyTimeoutDelayMillis();
+
/**
* Used by {@link LocationTimeZoneProviderController} to obtain information from the surrounding
* service. It can easily be faked for tests.
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
index ef2e349..f1d3723 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
@@ -21,6 +21,7 @@
import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneManagerService.PRIMARY_PROVIDER_NAME;
+import static com.android.server.location.timezone.LocationTimeZoneManagerService.SECONDARY_PROVIDER_NAME;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,7 +43,8 @@
*/
final class SimulatedBinderProviderEvent {
- private static final List<String> VALID_PROVIDER_NAMES = Arrays.asList(PRIMARY_PROVIDER_NAME);
+ private static final List<String> VALID_PROVIDER_NAMES =
+ Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME);
static final int INJECTED_EVENT_TYPE_ON_BIND = 1;
static final int INJECTED_EVENT_TYPE_ON_UNBIND = 2;
diff --git a/services/core/java/com/android/server/location/timezone/ThreadingDomain.java b/services/core/java/com/android/server/location/timezone/ThreadingDomain.java
index 9b9c823..d55d3ed 100644
--- a/services/core/java/com/android/server/location/timezone/ThreadingDomain.java
+++ b/services/core/java/com/android/server/location/timezone/ThreadingDomain.java
@@ -83,21 +83,14 @@
}
/**
- * A class that allows up to one {@link Runnable} to be queued on the handler, i.e. calling any
- * of the methods will cancel the execution of any previously queued / delayed runnable. All
+ * A class that allows up to one {@link Runnable} to be queued, i.e. calling {@link
+ * #runDelayed(Runnable, long)} will cancel the execution of any previously queued runnable. All
* methods must be called from the {@link ThreadingDomain}'s thread.
*/
final class SingleRunnableQueue {
- /**
- * Runs the supplied {@link Runnable} synchronously on the threading domain's thread,
- * cancelling any queued but not-yet-executed {@link Runnable} previously added by this.
- * This method must be called from the threading domain's thread.
- */
- void runSynchronously(Runnable r) {
- cancel();
- r.run();
- }
+ private boolean mIsQueued;
+ private long mDelayMillis;
/**
* Posts the supplied {@link Runnable} asynchronously and delayed on the threading domain
@@ -106,15 +99,48 @@
*/
void runDelayed(Runnable r, long delayMillis) {
cancel();
- ThreadingDomain.this.postDelayed(r, this, delayMillis);
+ mIsQueued = true;
+ mDelayMillis = delayMillis;
+ ThreadingDomain.this.postDelayed(() -> {
+ mIsQueued = false;
+ mDelayMillis = -2;
+ r.run();
+ }, this, delayMillis);
+ }
+
+ /**
+ * Returns {@code true} if there is an item current queued. This method must be called from
+ * the threading domain's thread.
+ */
+ boolean hasQueued() {
+ assertCurrentThread();
+ return mIsQueued;
+ }
+
+ /**
+ * Returns the delay in milliseconds for the currently queued item. Throws {@link
+ * IllegalStateException} if nothing is currently queued, see {@link #hasQueued()}.
+ * This method must be called from the threading domain's thread.
+ */
+ long getQueuedDelayMillis() {
+ assertCurrentThread();
+ if (!mIsQueued) {
+ throw new IllegalStateException("No item queued");
+ }
+ return mDelayMillis;
}
/**
* Cancels any queued but not-yet-executed {@link Runnable} previously added by this.
+ * This method must be called from the threading domain's thread.
*/
public void cancel() {
assertCurrentThread();
- removeQueuedRunnables(this);
+ if (mIsQueued) {
+ removeQueuedRunnables(this);
+ }
+ mIsQueued = false;
+ mDelayMillis = -1;
}
}
}
diff --git a/services/core/java/com/android/server/location/util/AlarmHelper.java b/services/core/java/com/android/server/location/util/AlarmHelper.java
new file mode 100644
index 0000000..46dbdbf
--- /dev/null
+++ b/services/core/java/com/android/server/location/util/AlarmHelper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.location.util;
+
+import android.app.AlarmManager.OnAlarmListener;
+import android.os.WorkSource;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helps manage alarms.
+ */
+public abstract class AlarmHelper {
+
+ /**
+ * Sets a wakeup alarm that will fire after the given delay.
+ */
+ public final void setDelayedAlarm(long delayMs, OnAlarmListener listener,
+ WorkSource workSource) {
+ // helps ensure that we're not wasting system resources by setting alarms in the past/now
+ Preconditions.checkArgument(delayMs > 0);
+ Preconditions.checkArgument(workSource != null);
+ setDelayedAlarmInternal(delayMs, listener, workSource);
+ }
+
+ protected abstract void setDelayedAlarmInternal(long delayMs, OnAlarmListener listener,
+ WorkSource workSource);
+
+ /**
+ * Cancels an alarm.
+ */
+ public abstract void cancel(OnAlarmListener listener);
+}
diff --git a/services/core/java/com/android/server/location/util/Injector.java b/services/core/java/com/android/server/location/util/Injector.java
index 379b303..6ebce91 100644
--- a/services/core/java/com/android/server/location/util/Injector.java
+++ b/services/core/java/com/android/server/location/util/Injector.java
@@ -17,7 +17,6 @@
package com.android.server.location.util;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.location.LocationRequestStatistics;
/**
* Injects various location dependencies so that they may be controlled by tests.
@@ -28,6 +27,9 @@
/** Returns a UserInfoHelper. */
UserInfoHelper getUserInfoHelper();
+ /** Returns an AlarmHelper. */
+ AlarmHelper getAlarmHelper();
+
/** Returns an AppOpsHelper. */
AppOpsHelper getAppOpsHelper();
@@ -52,6 +54,6 @@
/** Returns a LocationUsageLogger. */
LocationUsageLogger getLocationUsageLogger();
- /** Returns a LocationRequestStatistics. */
- LocationRequestStatistics getLocationRequestStatistics();
+ /** Returns a LocationEventLog. */
+ LocationEventLog getLocationEventLog();
}
diff --git a/services/core/java/com/android/server/location/util/LocationEventLog.java b/services/core/java/com/android/server/location/util/LocationEventLog.java
new file mode 100644
index 0000000..e4c354b
--- /dev/null
+++ b/services/core/java/com/android/server/location/util/LocationEventLog.java
@@ -0,0 +1,313 @@
+/*
+ * 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.location.util;
+
+import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
+import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_NO_CHANGE;
+import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+
+import android.annotation.Nullable;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Build;
+import android.os.PowerManager.LocationPowerSaveMode;
+
+import com.android.internal.location.ProviderRequest;
+import com.android.server.location.LocationManagerService;
+import com.android.server.utils.eventlog.LocalEventLog;
+
+/** In memory event log for location events. */
+public class LocationEventLog extends LocalEventLog {
+
+ private static int getLogSize() {
+ if (Build.IS_DEBUGGABLE || LocationManagerService.D) {
+ return 500;
+ } else {
+ return 200;
+ }
+ }
+
+ private static final int EVENT_LOCATION_ENABLED = 1;
+ private static final int EVENT_PROVIDER_ENABLED = 2;
+ private static final int EVENT_PROVIDER_MOCKED = 3;
+ private static final int EVENT_PROVIDER_REGISTER_CLIENT = 4;
+ private static final int EVENT_PROVIDER_UNREGISTER_CLIENT = 5;
+ private static final int EVENT_PROVIDER_UPDATE_REQUEST = 6;
+ private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 7;
+ private static final int EVENT_PROVIDER_DELIVER_LOCATION = 8;
+ private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 9;
+
+ public LocationEventLog() {
+ super(getLogSize());
+ }
+
+ /** Logs a location enabled/disabled event. */
+ public synchronized void logLocationEnabled(int userId, boolean enabled) {
+ addLogEvent(EVENT_LOCATION_POWER_SAVE_MODE_CHANGE, userId, enabled);
+ }
+
+ /** Logs a location provider enabled/disabled event. */
+ public synchronized void logProviderEnabled(String provider, int userId, boolean enabled) {
+ addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
+ }
+
+ /** Logs a location provider being replaced/unreplaced by a mock provider. */
+ public synchronized void logProviderMocked(String provider, boolean mocked) {
+ addLogEvent(EVENT_PROVIDER_MOCKED, provider, mocked);
+ }
+
+ /** Logs a new client registration for a location provider. */
+ public synchronized void logProviderClientRegistered(String provider, CallerIdentity identity,
+ LocationRequest request) {
+ addLogEvent(EVENT_PROVIDER_REGISTER_CLIENT, provider, identity, request);
+ }
+
+ /** Logs a client unregistration for a location provider. */
+ public synchronized void logProviderClientUnregistered(String provider,
+ CallerIdentity identity) {
+ addLogEvent(EVENT_PROVIDER_UNREGISTER_CLIENT, provider, identity);
+ }
+
+ /** Logs a change to the provider request for a location provider. */
+ public synchronized void logProviderUpdateRequest(String provider, ProviderRequest request) {
+ addLogEvent(EVENT_PROVIDER_UPDATE_REQUEST, provider, request);
+ }
+
+ /** Logs a new incoming location for a location provider. */
+ public synchronized void logProviderReceivedLocation(String provider) {
+ addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider);
+ }
+
+ /** Logs a location deliver for a client of a location provider. */
+ public synchronized void logProviderDeliveredLocation(String provider,
+ CallerIdentity identity) {
+ addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, identity);
+ }
+
+ /** Logs that the location power save mode has changed. */
+ public synchronized void logLocationPowerSaveMode(
+ @LocationPowerSaveMode int locationPowerSaveMode) {
+ addLogEvent(EVENT_LOCATION_POWER_SAVE_MODE_CHANGE, locationPowerSaveMode);
+ }
+
+ @Override
+ protected LogEvent createLogEvent(long timeDelta, int event, Object... args) {
+ switch (event) {
+ case EVENT_LOCATION_ENABLED:
+ return new LocationEnabledEvent(timeDelta, (Integer) args[1], (Boolean) args[2]);
+ case EVENT_PROVIDER_ENABLED:
+ return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
+ (Boolean) args[2]);
+ case EVENT_PROVIDER_MOCKED:
+ return new ProviderMockedEvent(timeDelta, (String) args[0], (Boolean) args[1]);
+ case EVENT_PROVIDER_REGISTER_CLIENT:
+ return new ProviderRegisterEvent(timeDelta, (String) args[0], true,
+ (CallerIdentity) args[1], (LocationRequest) args[2]);
+ case EVENT_PROVIDER_UNREGISTER_CLIENT:
+ return new ProviderRegisterEvent(timeDelta, (String) args[0], false,
+ (CallerIdentity) args[1], null);
+ case EVENT_PROVIDER_UPDATE_REQUEST:
+ return new ProviderUpdateEvent(timeDelta, (String) args[0],
+ (ProviderRequest) args[1]);
+ case EVENT_PROVIDER_RECEIVE_LOCATION:
+ return new ProviderReceiveLocationEvent(timeDelta, (String) args[0]);
+ case EVENT_PROVIDER_DELIVER_LOCATION:
+ return new ProviderDeliverLocationEvent(timeDelta, (String) args[0],
+ (CallerIdentity) args[1]);
+ case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE:
+ return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static class ProviderEnabledEvent extends LogEvent {
+
+ private final String mProvider;
+ private final int mUserId;
+ private final boolean mEnabled;
+
+ protected ProviderEnabledEvent(long timeDelta, String provider, int userId,
+ boolean enabled) {
+ super(timeDelta);
+ mProvider = provider;
+ mUserId = userId;
+ mEnabled = enabled;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider [u" + mUserId + "] " + (mEnabled ? "enabled"
+ : "disabled");
+ }
+ }
+
+ private static class ProviderMockedEvent extends LogEvent {
+
+ private final String mProvider;
+ private final boolean mMocked;
+
+ protected ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
+ super(timeDelta);
+ mProvider = provider;
+ mMocked = mocked;
+ }
+
+ @Override
+ public String getLogString() {
+ if (mMocked) {
+ return mProvider + " provider added mock provider override";
+ } else {
+ return mProvider + " provider removed mock provider override";
+ }
+ }
+ }
+
+ private static class ProviderRegisterEvent extends LogEvent {
+
+ private final String mProvider;
+ private final boolean mRegistered;
+ private final CallerIdentity mIdentity;
+ @Nullable private final LocationRequest mLocationRequest;
+
+ private ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
+ CallerIdentity identity, @Nullable LocationRequest locationRequest) {
+ super(timeDelta);
+ mProvider = provider;
+ mRegistered = registered;
+ mIdentity = identity;
+ mLocationRequest = locationRequest;
+ }
+
+ @Override
+ public String getLogString() {
+ if (mRegistered) {
+ return mProvider + " provider " + "+registration " + mIdentity + " -> "
+ + mLocationRequest;
+ } else {
+ return mProvider + " provider " + "-registration " + mIdentity;
+ }
+ }
+ }
+
+ private static class ProviderUpdateEvent extends LogEvent {
+
+ private final String mProvider;
+ private final ProviderRequest mRequest;
+
+ private ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
+ super(timeDelta);
+ mProvider = provider;
+ mRequest = request;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider request = " + mRequest;
+ }
+ }
+
+ private static class ProviderReceiveLocationEvent extends LogEvent {
+
+ private final String mProvider;
+
+ private ProviderReceiveLocationEvent(long timeDelta, String provider) {
+ super(timeDelta);
+ mProvider = provider;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider received location";
+ }
+ }
+
+ private static class ProviderDeliverLocationEvent extends LogEvent {
+
+ private final String mProvider;
+ @Nullable private final CallerIdentity mIdentity;
+
+ private ProviderDeliverLocationEvent(long timeDelta, String provider,
+ @Nullable CallerIdentity identity) {
+ super(timeDelta);
+ mProvider = provider;
+ mIdentity = identity;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider delivered location to " + mIdentity;
+ }
+ }
+
+ private static class LocationPowerSaveModeEvent extends LogEvent {
+
+ @LocationPowerSaveMode
+ private final int mLocationPowerSaveMode;
+
+ private LocationPowerSaveModeEvent(long timeDelta,
+ @LocationPowerSaveMode int locationPowerSaveMode) {
+ super(timeDelta);
+ mLocationPowerSaveMode = locationPowerSaveMode;
+ }
+
+ @Override
+ public String getLogString() {
+ String mode;
+ switch (mLocationPowerSaveMode) {
+ case LOCATION_MODE_NO_CHANGE:
+ mode = "NO_CHANGE";
+ break;
+ case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ mode = "GPS_DISABLED_WHEN_SCREEN_OFF";
+ break;
+ case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+ mode = "ALL_DISABLED_WHEN_SCREEN_OFF";
+ break;
+ case LOCATION_MODE_FOREGROUND_ONLY:
+ mode = "FOREGROUND_ONLY";
+ break;
+ case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+ mode = "THROTTLE_REQUESTS_WHEN_SCREEN_OFF";
+ break;
+ default:
+ mode = "UNKNOWN";
+ break;
+ }
+ return "location power save mode changed to " + mode;
+ }
+ }
+
+ private static class LocationEnabledEvent extends LogEvent {
+
+ private final int mUserId;
+ private final boolean mEnabled;
+
+ private LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
+ super(timeDelta);
+ mUserId = userId;
+ mEnabled = enabled;
+ }
+
+ @Override
+ public String getLogString() {
+ return "[u" + mUserId + "] location setting " + (mEnabled ? "enabled" : "disabled");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/util/LocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/util/LocationPowerSaveModeHelper.java
index a9a8c50..d85ca5e 100644
--- a/services/core/java/com/android/server/location/util/LocationPowerSaveModeHelper.java
+++ b/services/core/java/com/android/server/location/util/LocationPowerSaveModeHelper.java
@@ -35,9 +35,11 @@
void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode);
}
+ private final LocationEventLog mLocationEventLog;
private final CopyOnWriteArrayList<LocationPowerSaveModeChangedListener> mListeners;
- public LocationPowerSaveModeHelper() {
+ public LocationPowerSaveModeHelper(LocationEventLog locationEventLog) {
+ mLocationEventLog = locationEventLog;
mListeners = new CopyOnWriteArrayList<>();
}
@@ -58,6 +60,7 @@
protected final void notifyLocationPowerSaveModeChanged(
@LocationPowerSaveMode int locationPowerSaveMode) {
+ mLocationEventLog.logLocationPowerSaveMode(locationPowerSaveMode);
for (LocationPowerSaveModeChangedListener listener : mListeners) {
listener.onLocationPowerSaveModeChanged(locationPowerSaveMode);
}
diff --git a/services/core/java/com/android/server/location/util/SystemAlarmHelper.java b/services/core/java/com/android/server/location/util/SystemAlarmHelper.java
new file mode 100644
index 0000000..81849794
--- /dev/null
+++ b/services/core/java/com/android/server/location/util/SystemAlarmHelper.java
@@ -0,0 +1,57 @@
+/*
+ * 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.location.util;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.SystemClock;
+import android.os.WorkSource;
+
+import com.android.server.FgThread;
+
+import java.util.Objects;
+
+/**
+ * Provides helpers for alarms.
+ */
+public class SystemAlarmHelper extends AlarmHelper {
+
+ private final Context mContext;
+
+ public SystemAlarmHelper(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void setDelayedAlarmInternal(long delayMs, AlarmManager.OnAlarmListener listener,
+ WorkSource workSource) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayMs,
+ WINDOW_EXACT, 0, listener, FgThread.getHandler(), workSource);
+ }
+
+ @Override
+ public void cancel(AlarmManager.OnAlarmListener listener) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.cancel(listener);
+ }
+}
diff --git a/services/core/java/com/android/server/location/util/SystemLocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/util/SystemLocationPowerSaveModeHelper.java
index c8d8202..3129eba 100644
--- a/services/core/java/com/android/server/location/util/SystemLocationPowerSaveModeHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemLocationPowerSaveModeHelper.java
@@ -41,7 +41,8 @@
@LocationPowerSaveMode
private volatile int mLocationPowerSaveMode;
- public SystemLocationPowerSaveModeHelper(Context context) {
+ public SystemLocationPowerSaveModeHelper(Context context, LocationEventLog locationEventLog) {
+ super(locationEventLog);
mContext = context;
}
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index ddd56c8..82b0f9c 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -20,9 +20,9 @@
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.ServiceManager;
@@ -34,7 +34,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -203,9 +202,9 @@
private void processPendingLockoutsForFingerprint(List<UserAuthInfo> pendingResetLockouts) {
if (mFingerprintManager != null) {
- final List<FingerprintSensorProperties> fingerprintSensorProperties =
- mFingerprintManager.getSensorProperties();
- for (FingerprintSensorProperties prop : fingerprintSensorProperties) {
+ final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
+ mFingerprintManager.getSensorPropertiesInternal();
+ for (FingerprintSensorPropertiesInternal prop : fingerprintSensorProperties) {
if (!prop.resetLockoutRequiresHardwareAuthToken) {
for (UserAuthInfo user : pendingResetLockouts) {
mFingerprintManager.resetLockout(prop.sensorId, user.userId,
@@ -238,16 +237,16 @@
Slog.w(TAG, "mFaceGenerateChallengeCallback not null, previous operation may be"
+ " stuck");
}
- final List<FaceSensorProperties> faceSensorProperties =
- mFaceManager.getSensorProperties();
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ mFaceManager.getSensorPropertiesInternal();
final Set<Integer> sensorIds = new ArraySet<>();
- for (FaceSensorProperties prop : faceSensorProperties) {
+ for (FaceSensorPropertiesInternal prop : faceSensorProperties) {
sensorIds.add(prop.sensorId);
}
mFaceResetLockoutTask = new FaceResetLockoutTask(mFaceFinishCallback, mFaceManager,
mSpManager, sensorIds, pendingResetLockouts);
- for (final FaceSensorProperties prop : faceSensorProperties) {
+ for (final FaceSensorPropertiesInternal prop : faceSensorProperties) {
// Generate a challenge for each sensor. The challenge does not need to be
// per-user, since the HAT returned by gatekeeper contains userId.
mFaceManager.generateChallenge(prop.sensorId, mFaceResetLockoutTask);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0450e5b..2992877 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -587,7 +587,7 @@
private final NetworkPolicyLogger mLogger = new NetworkPolicyLogger();
- /** List of apps indexed by appId and whether they have the internet permission */
+ /** List of apps indexed by uid and whether they have the internet permission */
@GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray();
@@ -973,7 +973,7 @@
if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
// Clear the cache for the app
synchronized (mUidRulesFirstLock) {
- mInternetPermissionMap.delete(UserHandle.getAppId(uid));
+ mInternetPermissionMap.delete(uid);
updateRestrictionRulesForUidUL(uid);
}
}
@@ -4203,16 +4203,14 @@
@GuardedBy("mUidRulesFirstLock")
private boolean hasInternetPermissionUL(int uid) {
try {
- final int appId = UserHandle.getAppId(uid);
- final boolean hasPermission;
- if (mInternetPermissionMap.indexOfKey(appId) < 0) {
- hasPermission =
- mIPm.checkUidPermission(Manifest.permission.INTERNET, uid)
- == PackageManager.PERMISSION_GRANTED;
- mInternetPermissionMap.put(appId, hasPermission);
- } else {
- hasPermission = mInternetPermissionMap.get(appId);
+ if (mInternetPermissionMap.get(uid)) {
+ return true;
}
+ // If the cache shows that uid doesn't have internet permission,
+ // then always re-check with PackageManager just to be safe.
+ final boolean hasPermission = mIPm.checkUidPermission(Manifest.permission.INTERNET,
+ uid) == PackageManager.PERMISSION_GRANTED;
+ mInternetPermissionMap.put(uid, hasPermission);
return hasPermission;
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index a4a94c2..25ad9280 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -271,7 +271,7 @@
new Intent(ACTION_EVALUATE)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_TIME, time),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
alarms.cancel(pendingIntent);
if (time == 0 || time < now) {
if (DEBUG) Slog.d(TAG, "Not scheduling evaluate: " + (time == 0 ? "no time specified"
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b4c98e0..4da5fad 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3084,6 +3084,8 @@
UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
}
+ mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
+ enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
try {
getContext().sendBroadcastAsUser(
new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
@@ -5247,7 +5249,8 @@
Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
if (appIntent != null) {
summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
- getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
+ getContext(), 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
+ UserHandle.of(userId));
}
final StatusBarNotification summarySbn =
new StatusBarNotification(adjustedSbn.getPackageName(),
@@ -6830,7 +6833,7 @@
.appendPath(record.getKey()).build())
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_KEY, record.getKey()),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
}
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 961d3db..3517033 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -223,7 +223,7 @@
new Intent(ACTION_EVALUATE)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_TIME, time),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
alarms.cancel(pendingIntent);
if (time > now) {
if (DEBUG) Slog.d(TAG, String.format("Scheduling evaluate for %s, in %s, now=%s",
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index bee9ef9..2aafe9a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1087,6 +1087,23 @@
}
}
+ private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode)
+ throws IOException, ErrnoException {
+ // TODO: this should delegate to DCS so the system process avoids
+ // holding open FDs into containers.
+ final FileDescriptor fd = Os.open(path, flags, mode);
+ return new ParcelFileDescriptor(fd);
+ }
+
+ private ParcelFileDescriptor createRevocableFdInternal(RevocableFileDescriptor fd,
+ ParcelFileDescriptor pfd) throws IOException {
+ int releasedFdInt = pfd.detachFd();
+ FileDescriptor releasedFd = new FileDescriptor();
+ releasedFd.setInt$(releasedFdInt);
+ fd.init(mContext, releasedFd);
+ return fd.getRevocableFileDescriptor();
+ }
+
private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
ParcelFileDescriptor incomingFd) throws IOException {
// Quick validity check of state, and allocate a pipe for ourselves. We
@@ -1119,21 +1136,20 @@
Binder.restoreCallingIdentity(identity);
}
- // TODO: this should delegate to DCS so the system process avoids
- // holding open FDs into containers.
- final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
+ ParcelFileDescriptor targetPfd = openTargetInternal(target.getAbsolutePath(),
O_CREAT | O_WRONLY, 0644);
Os.chmod(target.getAbsolutePath(), 0644);
// If caller specified a total length, allocate it for them. Free up
// cache space to grow, if needed.
if (stageDir != null && lengthBytes > 0) {
- mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
+ mContext.getSystemService(StorageManager.class).allocateBytes(
+ targetPfd.getFileDescriptor(), lengthBytes,
PackageHelper.translateAllocateFlags(params.installFlags));
}
if (offsetBytes > 0) {
- Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
+ Os.lseek(targetPfd.getFileDescriptor(), offsetBytes, OsConstants.SEEK_SET);
}
if (incomingFd != null) {
@@ -1143,8 +1159,9 @@
// inserted above to hold the session active.
try {
final Int64Ref last = new Int64Ref(0);
- FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
- Runnable::run, (long progress) -> {
+ FileUtils.copy(incomingFd.getFileDescriptor(), targetPfd.getFileDescriptor(),
+ lengthBytes, null, Runnable::run,
+ (long progress) -> {
if (params.sizeBytes > 0) {
final long delta = progress - last.value;
last.value = progress;
@@ -1155,7 +1172,7 @@
}
});
} finally {
- IoUtils.closeQuietly(targetFd);
+ IoUtils.closeQuietly(targetPfd);
IoUtils.closeQuietly(incomingFd);
// We're done here, so remove the "bridge" that was holding
@@ -1171,12 +1188,11 @@
}
return null;
} else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
- fd.init(mContext, targetFd);
- return fd.getRevocableFileDescriptor();
+ return createRevocableFdInternal(fd, targetPfd);
} else {
- bridge.setTargetFile(targetFd);
+ bridge.setTargetFile(targetPfd);
bridge.start();
- return new ParcelFileDescriptor(bridge.getClientSocket());
+ return bridge.getClientSocket();
}
} catch (ErrnoException e) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 93b567f..cc1ef86 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20,10 +20,8 @@
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
@@ -92,7 +90,6 @@
import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
@@ -3779,6 +3776,8 @@
PackageParser.readConfigUseRoundIcon(mContext.getResources());
mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
+
+ Slog.i(TAG, "Fix for b/169414761 is applied");
}
/**
@@ -21918,24 +21917,18 @@
mInjector.getStorageManagerInternal().addExternalStoragePolicy(
new StorageManagerInternal.ExternalStorageMountPolicy() {
- @Override
- public int getMountMode(int uid, String packageName) {
- if (Process.isIsolated(uid)) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- }
- if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
- if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
- return Zygote.MOUNT_EXTERNAL_READ;
- }
- return Zygote.MOUNT_EXTERNAL_WRITE;
- }
+ @Override
+ public int getMountMode(int uid, String packageName) {
+ if (Process.isIsolated(uid)) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
+ }
- @Override
- public boolean hasExternalStorage(int uid, String packageName) {
- return true;
- }
+ @Override
+ public boolean hasExternalStorage(int uid, String packageName) {
+ return true;
+ }
});
// Now that we're mostly running, clean up stale users and apps
@@ -25893,7 +25886,7 @@
// This API is exposed temporarily to only the contacts provider. (b/158688602)
final int callingUid = Binder.getCallingUid();
ProviderInfo contactsProvider = resolveContentProviderInternal(
- ContactsContract.AUTHORITY, 0, UserHandle.USER_SYSTEM);
+ ContactsContract.AUTHORITY, 0, UserHandle.getUserId(callingUid));
if (contactsProvider == null || contactsProvider.applicationInfo == null
|| !UserHandle.isSameApp(contactsProvider.applicationInfo.uid, callingUid)) {
throw new SecurityException(callingUid + " is not allow to call grantImplicitAccess");
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6b29129..0a8c8f6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1729,6 +1729,7 @@
}
public void makeInitialized(@UserIdInt int userId) {
+ if (DBG) Slog.d(LOG_TAG, "makeInitialized(" + userId + ")");
checkManageUsersPermission("makeInitialized");
boolean scheduleWriteUser = false;
UserData userData;
@@ -3553,8 +3554,7 @@
// Must start user (which will be stopped right away, through
// UserController.finishUserUnlockedCompleted) so services can properly
// intialize it.
- // TODO(b/143092698): in the long-term, it might be better to add a onCreateUser()
- // callback on SystemService instead.
+ // NOTE: user will be stopped on UserController.finishUserUnlockedCompleted().
Slog.i(LOG_TAG, "starting pre-created user " + userInfo.toFullString());
final IActivityManager am = ActivityManager.getService();
try {
@@ -4965,6 +4965,9 @@
UserData userData = getUserDataNoChecks(userId);
if (userData != null) {
writeUserLP(userData);
+ } else {
+ Slog.i(LOG_TAG, "handle(WRITE_USER_MSG): no data for user " + userId
+ + ", it was probably removed before handler could handle it");
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 524f9ac..eb06bf9 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -36,13 +36,14 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.util.ArrayUtils;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageSettingBase;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -95,7 +96,8 @@
int uid;
/** Additional GIDs given to apps granted this permission */
- private int[] gids;
+ @NonNull
+ private int[] gids = EmptyArray.INT;
/**
* Flag indicating that {@link #gids} should be adjusted based on the
@@ -132,7 +134,7 @@
public int getUid() {
return uid;
}
- public void setGids(int[] gids, boolean perUser) {
+ public void setGids(@NonNull int[] gids, boolean perUser) {
this.gids = gids;
this.perUser = perUser;
}
@@ -141,18 +143,20 @@
}
public boolean hasGids() {
- return !ArrayUtils.isEmpty(gids);
+ return gids.length != 0;
}
+ @NonNull
public int[] computeGids(int userId) {
if (perUser) {
final int[] userGids = new int[gids.length];
for (int i = 0; i < gids.length; i++) {
- userGids[i] = UserHandle.getUid(userId, gids[i]);
+ final int gid = gids[i];
+ userGids[i] = UserHandle.getUid(userId, gid);
}
return userGids;
} else {
- return gids;
+ return gids.length != 0 ? gids.clone() : gids;
}
}
@@ -206,6 +210,11 @@
return perm != null && (perm.getFlags() & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
}
+ public boolean isInstallerExemptIgnored() {
+ return perm != null
+ && (perm.getFlags() & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
+ }
+
public boolean isSignature() {
return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
PermissionInfo.PROTECTION_SIGNATURE;
@@ -286,7 +295,8 @@
pendingPermissionInfo.packageName = newPackageName;
}
uid = 0;
- setGids(null, false);
+ gids = EmptyArray.INT;
+ perUser = false;
}
public boolean addToTree(@ProtectionLevel int protectionLevel,
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 474ce7c..0a514fa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -24,12 +24,14 @@
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -53,7 +55,6 @@
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-import static com.android.server.pm.permission.UidPermissionState.PERMISSION_OPERATION_FAILURE;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -103,7 +104,6 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
-import android.os.storage.StorageManagerInternal;
import android.permission.IOnPermissionsChangeListener;
import android.permission.IPermissionManager;
import android.permission.PermissionControllerManager;
@@ -152,6 +152,8 @@
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
+import libcore.util.EmptyArray;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -245,6 +247,7 @@
private final SparseArray<ArraySet<String>> mSystemPermissions;
/** Built-in group IDs given to all packages. Read from system configuration files. */
+ @NonNull
private final int[] mGlobalGids;
private final HandlerThread mHandlerThread;
@@ -785,6 +788,10 @@
throw new IllegalArgumentException("Unknown permission: " + permName);
}
+ if (bp.isInstallerExemptIgnored()) {
+ flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ }
+
final UidPermissionState uidState = getUidState(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
@@ -1096,7 +1103,8 @@
Preconditions.checkFlagsArgument(flags,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+ | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
Preconditions.checkArgumentNonNegative(userId, null);
if (UserHandle.getCallingUserId() != userId) {
@@ -1120,16 +1128,16 @@
final boolean isCallerInstallerOnRecord =
mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
- if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
- && !isCallerPrivileged) {
- throw new SecurityException("Querying system whitelist requires "
+ if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0 && !isCallerPrivileged) {
+ throw new SecurityException("Querying system or role allowlist requires "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) != 0) {
if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
- throw new SecurityException("Querying upgrade or installer whitelist"
+ throw new SecurityException("Querying upgrade or installer allowlist"
+ " requires being installer on record or "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
@@ -1153,6 +1161,9 @@
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
+ if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
+ queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ }
ArrayList<String> whitelistedPermissions = null;
@@ -1245,7 +1256,8 @@
Preconditions.checkFlagsArgument(flags,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+ | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
Preconditions.checkArgument(Integer.bitCount(flags) == 1);
Preconditions.checkArgumentNonNegative(userId, null);
@@ -1271,15 +1283,16 @@
final boolean isCallerInstallerOnRecord =
mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
- if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+ if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0
&& !isCallerPrivileged) {
- throw new SecurityException("Modifying system whitelist requires "
+ throw new SecurityException("Modifying system or role allowlist requires "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
- throw new SecurityException("Modifying upgrade whitelist requires"
+ throw new SecurityException("Modifying upgrade allowlist requires"
+ " being installer on record or "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
@@ -1501,7 +1514,7 @@
// normal runtime permissions. For now they apply to all users.
// TODO(zhanghai): We are breaking the behavior above by making all permission state
// per-user. It isn't documented behavior and relatively rarely used anyway.
- if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
+ if (uidState.grantPermission(bp)) {
if (callback != null) {
callback.onInstallPermissionGranted();
}
@@ -1519,18 +1532,14 @@
return;
}
- final int result = uidState.grantPermission(bp);
- switch (result) {
- case PERMISSION_OPERATION_FAILURE: {
- return;
- }
+ if (!uidState.grantPermission(bp)) {
+ return;
+ }
- case UidPermissionState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
- if (callback != null) {
- callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
- }
+ if (bp.hasGids()) {
+ if (callback != null) {
+ callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
}
- break;
}
if (bp.isRuntime()) {
@@ -1544,24 +1553,6 @@
if (bp.isRuntime()) {
notifyRuntimePermissionStateChanged(packageName, userId);
}
-
- // Only need to do this if user is initialized. Otherwise it's a new user
- // and there are no processes running as the user yet and there's no need
- // to make an expensive call to remount processes for the changed permissions.
- if (READ_EXTERNAL_STORAGE.equals(permName)
- || WRITE_EXTERNAL_STORAGE.equals(permName)) {
- final long token = Binder.clearCallingIdentity();
- try {
- if (mUserManagerInt.isUserInitialized(userId)) {
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
}
@Override
@@ -1650,7 +1641,7 @@
// normal runtime permissions. For now they apply to all users.
// TODO(zhanghai): We are breaking the behavior above by making all permission state
// per-user. It isn't documented behavior and relatively rarely used anyway.
- if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
+ if (uidState.revokePermission(bp)) {
if (callback != null) {
mDefaultPermissionCallback.onInstallPermissionRevoked();
}
@@ -1658,12 +1649,7 @@
return;
}
- // Permission is already revoked, no need to do anything.
- if (!uidState.isPermissionGranted(permName)) {
- return;
- }
-
- if (uidState.revokePermission(bp) == PERMISSION_OPERATION_FAILURE) {
+ if (!uidState.revokePermission(bp)) {
return;
}
@@ -2077,6 +2063,15 @@
return false;
}
+ BasePermission permission = getPermission(permName);
+ if (permission == null) {
+ return false;
+ }
+ if (permission.isHardRestricted()
+ && (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
+ return false;
+ }
+
final long token = Binder.clearCallingIdentity();
try {
if (permName.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
@@ -2504,11 +2499,11 @@
}
}
- @Nullable
+ @NonNull
private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
BasePermission permission = mSettings.getPermission(permissionName);
if (permission == null) {
- return null;
+ return EmptyArray.INT;
}
return permission.computeGids(userId);
}
@@ -2629,8 +2624,6 @@
}
}
- uidState.setGlobalGids(mGlobalGids);
-
ArraySet<String> newImplicitPermissions = new ArraySet<>();
final String friendlyName = pkg.getPackageName() + "(" + pkg.getUid() + ")";
@@ -2765,7 +2758,7 @@
switch (grant) {
case GRANT_INSTALL: {
// Grant an install permission.
- if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
+ if (uidState.grantPermission(bp)) {
changedInstallPermission = true;
}
} break;
@@ -2797,8 +2790,7 @@
if (permissionPolicyInitialized && hardRestricted) {
if (!restrictionExempt) {
if (origPermState != null && origPermState.isGranted()
- && uidState.revokePermission(
- bp) != PERMISSION_OPERATION_FAILURE) {
+ && uidState.revokePermission(bp)) {
wasChanged = true;
}
if (!restrictionApplied) {
@@ -2830,8 +2822,7 @@
|| (!hardRestricted || restrictionExempt)) {
if ((origPermState != null && origPermState.isGranted())
|| upgradedActivityRecognitionPermission != null) {
- if (uidState.grantPermission(bp)
- == PERMISSION_OPERATION_FAILURE) {
+ if (!uidState.grantPermission(bp)) {
wasChanged = true;
}
}
@@ -2850,8 +2841,7 @@
}
if (!uidState.isPermissionGranted(bp.name)
- && uidState.grantPermission(bp)
- != PERMISSION_OPERATION_FAILURE) {
+ && uidState.grantPermission(bp)) {
wasChanged = true;
}
@@ -2899,13 +2889,11 @@
} break;
}
} else {
- if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
- // Also drop the permission flags.
- uidState.updatePermissionFlags(bp,
- MASK_PERMISSION_FLAGS_ALL, 0);
- changedInstallPermission = true;
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Un-granting permission " + perm
+ if (DEBUG_PERMISSIONS) {
+ boolean wasGranted = uidState.isPermissionGranted(bp.name);
+ if (wasGranted || bp.isAppOp()) {
+ Slog.i(TAG, (wasGranted ? "Un-granting" : "Not granting")
+ + " permission " + perm
+ " from package " + friendlyName
+ " (protectionLevel=" + bp.getProtectionLevel()
+ " flags=0x"
@@ -2913,20 +2901,9 @@
ps))
+ ")");
}
- } else if (bp.isAppOp()) {
- // Don't print warning for app op permissions, since it is fine for them
- // not to be granted, there is a UI for the user to decide.
- if (DEBUG_PERMISSIONS
- && (packageOfInterest == null
- || packageOfInterest.equals(pkg.getPackageName()))) {
- Slog.i(TAG, "Not granting permission " + perm
- + " to package " + friendlyName
- + " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x"
- + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
- ps))
- + ")");
- }
+ }
+ if (uidState.removePermissionState(bp.name)) {
+ changedInstallPermission = true;
}
}
}
@@ -3005,8 +2982,7 @@
if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
&& supportsRuntimePermissions) {
- int revokeResult = ps.revokePermission(bp);
- if (revokeResult != PERMISSION_OPERATION_FAILURE) {
+ if (ps.revokePermission(bp)) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Revoking runtime permission "
+ permission + " for " + pkgName
@@ -3730,6 +3706,15 @@
}
}
break;
+ case FLAG_PERMISSION_ALLOWLIST_ROLE: {
+ mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ } else {
+ newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ }
+ }
+ break;
}
}
@@ -3865,14 +3850,9 @@
}
}
- // The package is gone - no need to keep flags for applying policy.
- uidState.updatePermissionFlags(bp, PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
-
- // Try to revoke as a runtime permission which is per user.
- // TODO(zhanghai): This doesn't make sense. revokePermission() doesn't fail, and why are
- // we only killing the uid when gids changed, instead of any permission change?
- if (uidState.revokePermission(bp)
- == UidPermissionState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ // TODO(zhanghai): Why are we only killing the UID when GIDs changed, instead of any
+ // permission change?
+ if (uidState.removePermissionState(bp.name) && bp.hasGids()) {
affectedUserId = userId;
}
}
@@ -3905,17 +3885,14 @@
boolean runtimePermissionChanged = false;
// Prune permissions
- final List<com.android.server.pm.permission.PermissionState> permissionStates =
- uidState.getPermissionStates();
+ final List<PermissionState> permissionStates = uidState.getPermissionStates();
final int permissionStatesSize = permissionStates.size();
for (int i = permissionStatesSize - 1; i >= 0; i--) {
PermissionState permissionState = permissionStates.get(i);
if (!usedPermissions.contains(permissionState.getName())) {
BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
if (bp != null) {
- uidState.revokePermission(bp);
- uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, 0);
- if (permissionState.isRuntime()) {
+ if (uidState.removePermissionState(bp.name) && permissionState.isRuntime()) {
runtimePermissionChanged = true;
}
}
@@ -4178,11 +4155,7 @@
+ p.getPackageName() + " and user " + userId);
return;
}
- if (uidState.getPermissionState(bp.getName()) != null) {
- uidState.revokePermission(bp);
- uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL,
- 0);
- }
+ uidState.removePermissionState(bp.name);
}
});
}
@@ -4741,7 +4714,7 @@
Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId);
return EMPTY_INT_ARRAY;
}
- return uidState.computeGids(userId);
+ return uidState.computeGids(mGlobalGids, userId);
}
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@@ -4804,7 +4777,7 @@
@UserIdInt int userId) {
return PermissionManagerService.this.getGrantedPermissions(packageName, userId);
}
- @Nullable
+ @NonNull
@Override
public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
return PermissionManagerService.this.getPermissionGids(permissionName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java
index 38264c8..59b204f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionState.java
@@ -17,7 +17,6 @@
package com.android.server.pm.permission;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import com.android.internal.annotations.GuardedBy;
@@ -62,7 +61,7 @@
return mPermission.getName();
}
- @Nullable
+ @NonNull
public int[] computeGids(@UserIdInt int userId) {
return mPermission.computeGids(userId);
}
diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
index 06a7f8d..82ab954 100644
--- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
@@ -22,35 +22,19 @@
import android.content.pm.PackageManager;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* Permission state for a UID.
- * <p>
- * This class is also responsible for keeping track of the Linux GIDs per
- * user for a package or a shared user. The GIDs are computed as a set of
- * the GIDs for all granted permissions' GIDs on a per user basis.
*/
public final class UidPermissionState {
- /** The permission operation failed. */
- public static final int PERMISSION_OPERATION_FAILURE = -1;
-
- /** The permission operation succeeded and no gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS = 0;
-
- /** The permission operation succeeded and gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
-
- private static final int[] NO_GIDS = {};
-
@NonNull
private final Object mLock = new Object();
@@ -60,11 +44,6 @@
@Nullable
private ArrayMap<String, PermissionState> mPermissions;
- private boolean mPermissionReviewRequired;
-
- @NonNull
- private int[] mGlobalGids = NO_GIDS;
-
public UidPermissionState() {}
public UidPermissionState(@NonNull UidPermissionState other) {
@@ -80,12 +59,6 @@
mPermissions.put(name, new PermissionState(permissionState));
}
}
-
- mPermissionReviewRequired = other.mPermissionReviewRequired;
-
- if (other.mGlobalGids != NO_GIDS) {
- mGlobalGids = other.mGlobalGids.clone();
- }
}
}
@@ -96,8 +69,6 @@
synchronized (mLock) {
mMissing = false;
mPermissions = null;
- mPermissionReviewRequired = false;
- mGlobalGids = NO_GIDS;
invalidateCache();
}
}
@@ -156,8 +127,8 @@
/**
* Gets the state for a permission or null if none.
*
- * @param name the permission name.
- * @return the permission state.
+ * @param name the permission name
+ * @return the permission state
*/
@Nullable
public PermissionState getPermissionState(@NonNull String name) {
@@ -169,6 +140,22 @@
}
}
+ @NonNull
+ private PermissionState getOrCreatePermissionState(@NonNull BasePermission permission) {
+ synchronized (mLock) {
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
+ }
+ final String name = permission.getName();
+ PermissionState permissionState = mPermissions.get(name);
+ if (permissionState == null) {
+ permissionState = new PermissionState(permission);
+ mPermissions.put(name, permissionState);
+ }
+ return permissionState;
+ }
+ }
+
/**
* Get all permission states.
*
@@ -186,19 +173,44 @@
/**
* Put a permission state.
+ *
+ * @param permission the permission
+ * @param granted whether the permission is granted
+ * @param flags the permission flags
*/
- public void putPermissionState(@NonNull BasePermission permission, boolean isGranted,
- int flags) {
+ public void putPermissionState(@NonNull BasePermission permission, boolean granted, int flags) {
synchronized (mLock) {
- ensureNoPermissionState(permission.name);
- PermissionState permissionState = ensurePermissionState(permission);
- if (isGranted) {
+ final String name = permission.getName();
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
+ } else {
+ mPermissions.remove(name);
+ }
+ final PermissionState permissionState = new PermissionState(permission);
+ if (granted) {
permissionState.grant();
}
permissionState.updateFlags(flags, flags);
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- mPermissionReviewRequired = true;
+ mPermissions.put(name, permissionState);
+ }
+ }
+
+ /**
+ * Remove a permission state.
+ *
+ * @param name the permission name
+ * @return whether the permission state changed
+ */
+ public boolean removePermissionState(@NonNull String name) {
+ synchronized (mLock) {
+ if (mPermissions == null) {
+ return false;
}
+ boolean changed = mPermissions.remove(name) != null;
+ if (changed && mPermissions.isEmpty()) {
+ mPermissions = null;
+ }
+ return changed;
}
}
@@ -209,13 +221,8 @@
* @return whether the permission is granted
*/
public boolean isPermissionGranted(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- PermissionState permissionState = mPermissions.get(name);
- return permissionState != null && permissionState.isGranted();
- }
+ final PermissionState permissionState = getPermissionState(name);
+ return permissionState != null && permissionState.isGranted();
}
/**
@@ -246,61 +253,37 @@
/**
* Grant a permission.
*
- * @param permission the permission to grantt
- * @return the operation result, which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
+ * @param permission the permission to grant
+ * @return whether the permission grant state changed
*/
- public int grantPermission(@NonNull BasePermission permission) {
- if (isPermissionGranted(permission.getName())) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- PermissionState permissionState = ensurePermissionState(permission);
-
- if (!permissionState.grant()) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
+ public boolean grantPermission(@NonNull BasePermission permission) {
+ PermissionState permissionState = getOrCreatePermissionState(permission);
+ return permissionState.grant();
}
/**
* Revoke a permission.
*
* @param permission the permission to revoke
- * @return the operation result, which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
+ * @return whether the permission grant state changed
*/
- public int revokePermission(@NonNull BasePermission permission) {
+ public boolean revokePermission(@NonNull BasePermission permission) {
final String name = permission.getName();
- if (!isPermissionGranted(name)) {
- return PERMISSION_OPERATION_SUCCESS;
+ final PermissionState permissionState = getPermissionState(name);
+ if (permissionState == null) {
+ return false;
}
-
- PermissionState permissionState;
- synchronized (mLock) {
- permissionState = mPermissions.get(name);
+ final boolean changed = permissionState.revoke();
+ if (changed && permissionState.isDefault()) {
+ removePermissionState(name);
}
-
- if (!permissionState.revoke()) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- if (permissionState.isDefault()) {
- ensureNoPermissionState(name);
- }
-
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
+ return changed;
}
/**
* Get the flags for a permission.
*
- * @param name the permission name.
+ * @param name the permission name
* @return the permission flags
*/
public int getPermissionFlags(@NonNull String name) {
@@ -324,77 +307,40 @@
if (flagMask == 0) {
return false;
}
-
- synchronized (mLock) {
- final PermissionState permissionState = ensurePermissionState(permission);
- final int oldFlags = permissionState.getFlags();
-
- final boolean updated = permissionState.updateFlags(flagMask, flagValues);
- if (updated) {
- final int newFlags = permissionState.getFlags();
- if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- mPermissionReviewRequired = true;
- } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- if (mPermissionReviewRequired && !hasPermissionRequiringReview()) {
- mPermissionReviewRequired = false;
- }
- }
- }
- return updated;
+ final PermissionState permissionState = getOrCreatePermissionState(permission);
+ final boolean changed = permissionState.updateFlags(flagMask, flagValues);
+ if (changed && permissionState.isDefault()) {
+ removePermissionState(permission.name);
}
+ return changed;
}
public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) {
+ if (flagMask == 0) {
+ return false;
+ }
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
- boolean changed = false;
- final int permissionsSize = mPermissions.size();
- for (int i = 0; i < permissionsSize; i++) {
+ boolean anyChanged = false;
+ for (int i = mPermissions.size() - 1; i >= 0; i--) {
final PermissionState permissionState = mPermissions.valueAt(i);
- changed |= permissionState.updateFlags(flagMask, flagValues);
+ final boolean changed = permissionState.updateFlags(flagMask, flagValues);
+ if (changed && permissionState.isDefault()) {
+ mPermissions.removeAt(i);
+ }
+ anyChanged |= changed;
}
- return changed;
- }
- }
-
- @NonNull
- private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
- final String name = permission.getName();
- synchronized (mLock) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- PermissionState permissionState = mPermissions.get(name);
- if (permissionState == null) {
- permissionState = new PermissionState(permission);
- mPermissions.put(name, permissionState);
- }
- return permissionState;
- }
- }
-
- private void ensureNoPermissionState(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return;
- }
- mPermissions.remove(name);
- if (mPermissions.isEmpty()) {
- mPermissions = null;
- }
+ return anyChanged;
}
}
public boolean isPermissionReviewRequired() {
- return mPermissionReviewRequired;
- }
-
- private boolean hasPermissionRequiringReview() {
synchronized (mLock) {
+ if (mPermissions == null) {
+ return false;
+ }
final int permissionsSize = mPermissions.size();
for (int i = 0; i < permissionsSize; i++) {
final PermissionState permission = mPermissions.valueAt(i);
@@ -407,81 +353,31 @@
}
/**
- * Gets the global gids, applicable to all users.
- */
- @NonNull
- public int[] getGlobalGids() {
- return mGlobalGids;
- }
-
- /**
- * Sets the global gids, applicable to all users.
- *
- * @param globalGids The global gids.
- */
- public void setGlobalGids(@NonNull int[] globalGids) {
- if (!ArrayUtils.isEmpty(globalGids)) {
- mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
- } else {
- mGlobalGids = NO_GIDS;
- }
- }
-
- /**
* Compute the Linux GIDs from the permissions granted to a user.
*
* @param userId the user ID
* @return the GIDs for the user
*/
@NonNull
- public int[] computeGids(@UserIdInt int userId) {
- int[] gids = mGlobalGids;
-
+ public int[] computeGids(@NonNull int[] globalGids, @UserIdInt int userId) {
synchronized (mLock) {
- if (mPermissions != null) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionState permissionState = mPermissions.valueAt(i);
- if (!permissionState.isGranted()) {
- continue;
- }
- final int[] permGids = permissionState.computeGids(userId);
- if (permGids != NO_GIDS) {
- gids = appendInts(gids, permGids);
- }
+ IntArray gids = IntArray.wrap(globalGids);
+ if (mPermissions == null) {
+ return gids.toArray();
+ }
+ final int permissionsSize = mPermissions.size();
+ for (int i = 0; i < permissionsSize; i++) {
+ PermissionState permissionState = mPermissions.valueAt(i);
+ if (!permissionState.isGranted()) {
+ continue;
+ }
+ final int[] permissionGids = permissionState.computeGids(userId);
+ if (permissionGids.length != 0) {
+ gids.addAll(permissionGids);
}
}
+ return gids.toArray();
}
-
- return gids;
- }
-
- /**
- * Compute the Linux GIDs from the permissions granted to specified users.
- *
- * @param userIds the user IDs
- * @return the GIDs for the user
- */
- @NonNull
- public int[] computeGids(@NonNull int[] userIds) {
- int[] gids = mGlobalGids;
-
- for (final int userId : userIds) {
- final int[] userGids = computeGids(userId);
- gids = appendInts(gids, userGids);
- }
-
- return gids;
- }
-
- // TODO: fix this to use arraycopy and append all ints in one go
- private static int[] appendInts(int[] current, int[] added) {
- if (current != null && added != null) {
- for (int guid : added) {
- current = ArrayUtils.appendInt(current, guid);
- }
- }
- return current;
}
static void invalidateCache() {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 874b910..d1fd0ad 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -56,6 +56,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.os.TransferPipe;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -1510,6 +1511,23 @@
return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
}
+ /** @hide */
+ public void passThroughShellCommand(String[] args, FileDescriptor fd) {
+ enforceStatusBarOrShell();
+ if (mBar == null) return;
+
+ try (TransferPipe tp = new TransferPipe()) {
+ // Sending the command to the remote, which needs to execute async to avoid blocking
+ // See Binder#dumpAsync() for inspiration
+ tp.setBufferPrefix(" ");
+ mBar.passThroughShellCommand(args, tp.getWriteFd());
+ // Times out after 5s
+ tp.go(fd);
+ } catch (Throwable t) {
+ Slog.e(TAG, "Error sending command to IStatusBar", t);
+ }
+ }
+
// ================================================================================
// Can be called from any thread
// ================================================================================
diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
index a79c19f..6171822 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
@@ -46,7 +46,8 @@
@Override
public int onCommand(String cmd) {
if (cmd == null) {
- return handleDefaultCommands(cmd);
+ onHelp();
+ return 1;
}
try {
switch (cmd) {
@@ -74,8 +75,16 @@
return runSendDisableFlag();
case "tracing":
return runTracing();
+ // Handle everything that would be handled in `handleDefaultCommand()` explicitly,
+ // so the default can be to pass all args to StatusBar
+ case "-h":
+ case "help":
+ onHelp();
+ return 0;
+ case "dump":
+ return super.handleDefaultCommands(cmd);
default:
- return handleDefaultCommands(cmd);
+ return runPassArgsToStatusBar();
}
} catch (RemoteException e) {
final PrintWriter pw = getOutPrintWriter();
@@ -187,6 +196,11 @@
return 0;
}
+ private int runPassArgsToStatusBar() {
+ mInterface.passThroughShellCommand(getAllArgs(), getOutFileDescriptor());
+ return 0;
+ }
+
private int runTracing() {
switch (getNextArg()) {
case "start":
@@ -250,6 +264,12 @@
pw.println(" tracing (start | stop)");
pw.println(" Start or stop SystemUI tracing");
pw.println("");
+ pw.println(" NOTE: any command not listed here will be passed through to IStatusBar");
+ pw.println("");
+ pw.println(" Commands implemented in SystemUI:");
+ pw.flush();
+ // Sending null args to systemui will print help
+ mInterface.passThroughShellCommand(new String[] {}, getOutFileDescriptor());
}
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 3406bd9..70ab48b 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -84,6 +84,7 @@
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
new ContentObserver(handler) {
+ @Override
public void onChange(boolean selfChange) {
timeDetectorService.handleAutoTimeDetectionChanged();
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index fe0e82e..9c18aad 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -572,7 +572,7 @@
*/
@VisibleForTesting
@Nullable
- public NetworkTimeSuggestion findLatestValidNetworkSuggestionForTests() {
+ public synchronized NetworkTimeSuggestion findLatestValidNetworkSuggestionForTests() {
return findLatestValidNetworkSuggestion();
}
@@ -590,7 +590,7 @@
*/
@VisibleForTesting
@Nullable
- public NetworkTimeSuggestion getLatestNetworkSuggestion() {
+ public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
return mLastNetworkSuggestion.get();
}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index b68c54f..9e76bc1 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -16,15 +16,16 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.app.timezonedetector.TimeZoneCapabilities;
-import android.app.timezonedetector.TimeZoneConfiguration;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.os.UserHandle;
import java.util.Objects;
@@ -32,7 +33,7 @@
/**
* Holds all configuration values that affect time zone behavior and some associated logic, e.g.
* {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
- * #createCapabilities()}.
+ * #createCapabilitiesAndConfig()}.
*/
public final class ConfigurationInternal {
@@ -106,10 +107,15 @@
return false;
}
- /** Creates a {@link TimeZoneCapabilities} object using the configuration values. */
- public TimeZoneCapabilities createCapabilities() {
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
- .setConfiguration(asConfiguration());
+ /** Creates a {@link TimeZoneCapabilitiesAndConfig} object using the configuration values. */
+ public TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig() {
+ return new TimeZoneCapabilitiesAndConfig(asCapabilities(), asConfiguration());
+ }
+
+ @NonNull
+ private TimeZoneCapabilities asCapabilities() {
+ UserHandle userHandle = UserHandle.of(mUserId);
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userHandle);
boolean allowConfigDateTime = isUserConfigAllowed();
@@ -125,7 +131,7 @@
} else {
configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
}
- builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability);
+ builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
final int configureGeolocationDetectionEnabledCapability;
if (!deviceHasTimeZoneDetection) {
@@ -137,7 +143,8 @@
} else {
configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
}
- builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability);
+ builder.setConfigureGeoDetectionEnabledCapability(
+ configureGeolocationDetectionEnabledCapability);
// The ability to make manual time zone suggestions can also be restricted by policy. With
// the current logic above, this could lead to a situation where a device hardware does not
@@ -151,14 +158,14 @@
} else {
suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
}
- builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability);
+ builder.setSuggestManualTimeZoneCapability(suggestManualTimeZoneCapability);
return builder.build();
}
/** Returns a {@link TimeZoneConfiguration} from the configuration values. */
- public TimeZoneConfiguration asConfiguration() {
- return new TimeZoneConfiguration.Builder(mUserId)
+ private TimeZoneConfiguration asConfiguration() {
+ return new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
.setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
.build();
@@ -171,10 +178,10 @@
*/
public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
Builder builder = new Builder(this);
- if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) {
+ if (newConfiguration.hasIsAutoDetectionEnabled()) {
builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
}
- if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) {
+ if (newConfiguration.hasIsGeoDetectionEnabled()) {
builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
}
return builder.build();
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 6a12b7c..964dbec 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -23,7 +23,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
-import android.app.timezonedetector.TimeZoneConfiguration;
+import android.app.time.TimeZoneConfiguration;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -87,6 +87,7 @@
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
new ContentObserver(mHandler) {
+ @Override
public void onChange(boolean selfChange) {
handleConfigChangeOnHandlerThread();
}
@@ -97,6 +98,7 @@
Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
true,
new ContentObserver(mHandler) {
+ @Override
public void onChange(boolean selfChange) {
handleConfigChangeOnHandlerThread();
}
@@ -157,7 +159,7 @@
}
@Override
- public void storeConfiguration(TimeZoneConfiguration configuration) {
+ public void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration configuration) {
Objects.requireNonNull(configuration);
// Avoid writing the auto detection enabled setting for devices that do not support auto
@@ -169,7 +171,6 @@
setAutoDetectionEnabled(autoDetectionEnabled);
if (mGeoDetectionFeatureEnabled) {
- final int userId = configuration.getUserId();
final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 73322a6..6e1f89b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -18,18 +18,19 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.timezonedetector.ITimeZoneConfigurationListener;
+import android.app.time.ITimeZoneDetectorListener;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -41,7 +42,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Objects;
/**
@@ -109,10 +109,14 @@
@NonNull
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
- @GuardedBy("mConfigurationListeners")
+ /**
+ * Holds the listeners. The key is the {@link IBinder} associated with the listener, the value
+ * is the listener itself.
+ */
+ @GuardedBy("mListeners")
@NonNull
- private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners =
- new ArrayList<>();
+ private final ArrayMap<IBinder, ITimeZoneDetectorListener> mListeners =
+ new ArrayMap<>();
private static TimeZoneDetectorService create(
@NonNull Context context, @NonNull Handler handler,
@@ -133,20 +137,22 @@
mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
- // Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when
+ // Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
// the configuration changes for any reason.
mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
}
@Override
@NonNull
- public TimeZoneCapabilities getCapabilities() {
- enforceManageTimeZoneDetectorConfigurationPermission();
+ public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig() {
+ enforceManageTimeZoneDetectorPermission();
int userId = mCallerIdentityInjector.getCallingUserId();
long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities();
+ ConfigurationInternal configurationInternal =
+ mTimeZoneDetectorStrategy.getConfigurationInternal(userId);
+ return configurationInternal.createCapabilitiesAndConfig();
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -154,37 +160,34 @@
@Override
public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
- enforceManageTimeZoneDetectorConfigurationPermission();
+ enforceManageTimeZoneDetectorPermission();
Objects.requireNonNull(configuration);
int callingUserId = mCallerIdentityInjector.getCallingUserId();
- if (callingUserId != configuration.getUserId()) {
- return false;
- }
-
long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.updateConfiguration(configuration);
+ return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@Override
- public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
- enforceManageTimeZoneDetectorConfigurationPermission();
+ public void addListener(@NonNull ITimeZoneDetectorListener listener) {
+ enforceManageTimeZoneDetectorPermission();
Objects.requireNonNull(listener);
- synchronized (mConfigurationListeners) {
- if (mConfigurationListeners.contains(listener)) {
+ synchronized (mListeners) {
+ IBinder listenerBinder = listener.asBinder();
+ if (mListeners.containsKey(listenerBinder)) {
return;
}
try {
// Ensure the reference to the listener will be removed if the client process dies.
- listener.asBinder().linkToDeath(this, 0 /* flags */);
+ listenerBinder.linkToDeath(this, 0 /* flags */);
// Only add the listener if we can linkToDeath().
- mConfigurationListeners.add(listener);
+ mListeners.put(listenerBinder, listener);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
}
@@ -192,21 +195,22 @@
}
@Override
- public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
- enforceManageTimeZoneDetectorConfigurationPermission();
+ public void removeListener(@NonNull ITimeZoneDetectorListener listener) {
+ enforceManageTimeZoneDetectorPermission();
Objects.requireNonNull(listener);
- synchronized (mConfigurationListeners) {
+ synchronized (mListeners) {
+ IBinder listenerBinder = listener.asBinder();
boolean removedListener = false;
- if (mConfigurationListeners.remove(listener)) {
+ if (mListeners.remove(listenerBinder) != null) {
// Stop listening for the client process to die.
- listener.asBinder().unlinkToDeath(this, 0 /* flags */);
+ listenerBinder.unlinkToDeath(this, 0 /* flags */);
removedListener = true;
}
if (!removedListener) {
Slog.w(TAG, "Client asked to remove listener=" + listener
+ ", but no listeners were removed."
- + " mConfigurationListeners=" + mConfigurationListeners);
+ + " mListeners=" + mListeners);
}
}
}
@@ -218,19 +222,18 @@
}
/**
- * Called when one of the ITimeZoneConfigurationListener processes dies before calling
- * {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}.
+ * Called when one of the ITimeZoneDetectorListener processes dies before calling
+ * {@link #removeListener(ITimeZoneDetectorListener)}.
*/
@Override
public void binderDied(IBinder who) {
- synchronized (mConfigurationListeners) {
+ synchronized (mListeners) {
boolean removedListener = false;
- final int listenerCount = mConfigurationListeners.size();
+ final int listenerCount = mListeners.size();
for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
- ITimeZoneConfigurationListener listener =
- mConfigurationListeners.get(listenerIndex);
- if (listener.asBinder().equals(who)) {
- mConfigurationListeners.remove(listenerIndex);
+ IBinder listenerBinder = mListeners.keyAt(listenerIndex);
+ if (listenerBinder.equals(who)) {
+ mListeners.removeAt(listenerIndex);
removedListener = true;
break;
}
@@ -238,7 +241,7 @@
if (!removedListener) {
Slog.w(TAG, "Notified of binder death for who=" + who
+ ", but did not remove any listeners."
- + " mConfigurationListeners=" + mConfigurationListeners);
+ + " mConfigurationListeners=" + mListeners);
}
}
}
@@ -247,11 +250,10 @@
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
- synchronized (mConfigurationListeners) {
- final int listenerCount = mConfigurationListeners.size();
+ synchronized (mListeners) {
+ final int listenerCount = mListeners.size();
for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
- ITimeZoneConfigurationListener listener =
- mConfigurationListeners.get(listenerIndex);
+ ITimeZoneDetectorListener listener = mListeners.valueAt(listenerIndex);
try {
listener.onChange();
} catch (RemoteException e) {
@@ -302,11 +304,10 @@
ipw.flush();
}
- private void enforceManageTimeZoneDetectorConfigurationPermission() {
- // TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission.
+ private void enforceManageTimeZoneDetectorPermission() {
mContext.enforceCallingPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS,
- "manage time and time zone configuration");
+ android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
+ "manage time and time zone detection");
}
private void enforceSuggestGeolocationTimeZonePermission() {
@@ -333,7 +334,7 @@
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new TimeZoneDetectorShellCommand(this)).exec(
+ new TimeZoneDetectorShellCommand(this).exec(
this, in, out, err, args, callback, resultReceiver);
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index f944c56..0b1d6d7 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -17,9 +17,9 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
/**
@@ -96,7 +96,8 @@
* <p>This method returns {@code true} if the configuration was changed,
* {@code false} otherwise.
*/
- boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
+ boolean updateConfiguration(
+ @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
/**
* Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 8a42b18..781668b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -15,20 +15,21 @@
*/
package com.android.server.timezonedetector;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
import android.os.Handler;
import android.util.IndentingPrintWriter;
@@ -93,7 +94,7 @@
* All checks about user capabilities must be done by the caller and
* {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
*/
- void storeConfiguration(TimeZoneConfiguration newConfiguration);
+ void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfiguration);
}
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -240,27 +241,26 @@
}
@Override
- public synchronized boolean updateConfiguration(
+ public synchronized boolean updateConfiguration(@UserIdInt int userId,
@NonNull TimeZoneConfiguration requestedConfiguration) {
Objects.requireNonNull(requestedConfiguration);
- int userId = requestedConfiguration.getUserId();
- TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ getConfigurationInternal(userId).createCapabilitiesAndConfig();
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ TimeZoneConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
- // Create a new configuration builder, and copy across the mutable properties users are
- // able to modify. Other properties are therefore ignored.
final TimeZoneConfiguration newConfiguration =
- capabilities.applyUpdate(requestedConfiguration);
+ capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
if (newConfiguration == null) {
- // The changes could not be made due to
+ // The changes could not be made because the user's capabilities do not allow it.
return false;
}
// Store the configuration / notify as needed. This will cause the mCallback to invoke
// handleConfigChanged() asynchronously.
- mCallback.storeConfiguration(newConfiguration);
+ mCallback.storeConfiguration(userId, newConfiguration);
- TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration();
String logMsg = "Configuration changed:"
+ " oldConfiguration=" + oldConfiguration
+ ", newConfiguration=" + newConfiguration;
@@ -313,8 +313,10 @@
String timeZoneId = suggestion.getZoneId();
String cause = "Manual time suggestion received: suggestion=" + suggestion;
- TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
- if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) {
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ getConfigurationInternal(userId).createCapabilitiesAndConfig();
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ if (capabilities.getSuggestManualTimeZoneCapability() != CAPABILITY_POSSESSED) {
Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
+ ", capabilities=" + capabilities
+ ", timeZoneId=" + timeZoneId
@@ -605,7 +607,7 @@
ipw.println("mCallback.getCurrentUserId()=" + currentUserId);
ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId);
ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration);
- ipw.println("[Capabilities=" + configuration.createCapabilities() + "]");
+ ipw.println("[Capabilities=" + configuration.createCapabilitiesAndConfig() + "]");
ipw.println("mCallback.isDeviceTimeZoneInitialized()="
+ mCallback.isDeviceTimeZoneInitialized());
ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
@@ -644,7 +646,7 @@
* A method used to inspect strategy state during tests. Not intended for general use.
*/
@VisibleForTesting
- public GeolocationTimeZoneSuggestion getLatestGeolocationSuggestion() {
+ public synchronized GeolocationTimeZoneSuggestion getLatestGeolocationSuggestion() {
return mLatestGeoLocationSuggestion.get();
}
@@ -652,7 +654,7 @@
* A {@link TelephonyTimeZoneSuggestion} with additional qualifying metadata.
*/
@VisibleForTesting
- public static class QualifiedTelephonyTimeZoneSuggestion {
+ public static final class QualifiedTelephonyTimeZoneSuggestion {
@VisibleForTesting
public final TelephonyTimeZoneSuggestion suggestion;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index cfceaabf..7b044ed 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -77,6 +77,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -709,8 +710,7 @@
}
sessionState.isCurrent = false;
sessionState.currentChannel = null;
- notifyCurrentChannelInfosUpdatedLocked(
- userState, getCurrentTvChannelInfosInternalLocked(userState));
+ notifyCurrentChannelInfosUpdatedLocked(userState);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in releaseSession", e);
} finally {
@@ -851,15 +851,18 @@
}
}
- private void notifyCurrentChannelInfosUpdatedLocked(
- UserState userState, List<TvChannelInfo> infos) {
+ private void notifyCurrentChannelInfosUpdatedLocked(UserState userState) {
if (DEBUG) {
Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- userState.mCallbacks.getBroadcastItem(i).onCurrentTvChannelInfosUpdated(infos);
+ ITvInputManagerCallback callback = userState.mCallbacks.getBroadcastItem(i);
+ Pair<Integer, Integer> pidUid = userState.callbackPidUidMap.get(callback);
+ List<TvChannelInfo> infos = getCurrentTvChannelInfosInternalLocked(
+ userState, pidUid.first, pidUid.second);
+ callback.onCurrentTvChannelInfosUpdated(infos);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report updated current channel infos to callback", e);
}
@@ -1063,14 +1066,19 @@
@Override
public void registerCallback(final ITvInputManagerCallback callback, int userId) {
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "registerCallback");
+ int callingPid = Binder.getCallingPid();
+ int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+ "registerCallback");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
if (!userState.mCallbacks.register(callback)) {
Slog.e(TAG, "client process has already died");
+ } else {
+ userState.callbackPidUidMap.put(
+ callback, Pair.create(callingPid, callingUid));
}
}
} finally {
@@ -1087,6 +1095,7 @@
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.mCallbacks.unregister(callback);
+ userState.callbackPidUidMap.remove(callback);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1419,8 +1428,8 @@
@Override
public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "tune");
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, "tune");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1432,8 +1441,7 @@
if (sessionState != null) {
sessionState.isCurrent = true;
sessionState.currentChannel = channelUri;
- notifyCurrentChannelInfosUpdatedLocked(
- userState, getCurrentTvChannelInfosInternalLocked(userState));
+ notifyCurrentChannelInfosUpdatedLocked(userState);
}
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
@@ -2090,16 +2098,13 @@
@Override
public List<TvChannelInfo> getCurrentTvChannelInfos(@UserIdInt int userId) {
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "getTvCurrentChannelInfos");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- return getCurrentTvChannelInfosInternalLocked(userState);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ int callingPid = Binder.getCallingPid();
+ int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+ "getTvCurrentChannelInfos");
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ return getCurrentTvChannelInfosInternalLocked(userState, callingPid, callingUid);
}
}
@@ -2273,14 +2278,15 @@
}
}
- private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) {
+ private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(
+ UserState userState, int callingPid, int callingUid) {
List<TvChannelInfo> channelInfos = new ArrayList<>();
- boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission();
+ boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(callingPid, callingUid);
for (SessionState state : userState.sessionStateMap.values()) {
if (state.isCurrent) {
Integer appTag;
int appType;
- if (state.callingUid == Binder.getCallingUid()) {
+ if (state.callingUid == callingUid) {
appTag = APP_TAG_SELF;
appType = TvChannelInfo.APP_TYPE_SELF;
} else {
@@ -2322,8 +2328,8 @@
return false;
}
- private boolean hasAccessWatchedProgramsPermission() {
- return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
+ private boolean hasAccessWatchedProgramsPermission(int callingPid, int callingUid) {
+ return mContext.checkPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
}
@@ -2360,6 +2366,9 @@
private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
new RemoteCallbackList<ITvInputManagerCallback>();
+ private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
+ new HashMap<>();
+
// The token of a "main" TV input session.
private IBinder mainSessionToken = null;
@@ -2712,8 +2721,7 @@
mSessionState.isCurrent = true;
mSessionState.currentChannel = channelUri;
UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
- notifyCurrentChannelInfosUpdatedLocked(
- userState, getCurrentTvChannelInfosInternalLocked(userState));
+ notifyCurrentChannelInfosUpdatedLocked(userState);
try {
// TODO: Consider adding this channel change in the watch log. When we do
// that, how we can protect the watch log from malicious tv inputs should
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 39f6c59..f6acc64 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -115,7 +115,7 @@
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
private static final int MAX_PERSISTED_URI_GRANTS = 512;
- private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
+ private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
private final Object mLock = new Object();
private final H mH;
diff --git a/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
new file mode 100644
index 0000000..c160647
--- /dev/null
+++ b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
@@ -0,0 +1,338 @@
+/*
+ * 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.utils.eventlog;
+
+import android.os.SystemClock;
+import android.util.TimeUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An in-memory event log to support historical event information.
+ */
+public abstract class LocalEventLog implements Iterable<String> {
+
+ private interface Log {
+ // true if this is a filler element that should not be queried
+ boolean isFiller();
+ long getTimeDeltaMs();
+ String getLogString();
+ }
+
+ private static final class FillerEvent implements Log {
+
+ static final long MAX_TIME_DELTA = (1L << 32) - 1;
+
+ private final int mTimeDelta;
+
+ FillerEvent(long timeDelta) {
+ Preconditions.checkArgument(timeDelta >= 0);
+ mTimeDelta = (int) timeDelta;
+ }
+
+ @Override
+ public boolean isFiller() {
+ return true;
+ }
+
+ @Override
+ public long getTimeDeltaMs() {
+ return Integer.toUnsignedLong(mTimeDelta);
+ }
+
+ @Override
+ public String getLogString() {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * An abstraction of a log event to be implemented by subclasses.
+ */
+ public abstract static class LogEvent implements Log {
+
+ static final long MAX_TIME_DELTA = (1L << 32) - 1;
+
+ private final int mTimeDelta;
+
+ protected LogEvent(long timeDelta) {
+ Preconditions.checkArgument(timeDelta >= 0);
+ mTimeDelta = (int) timeDelta;
+ }
+
+ @Override
+ public final boolean isFiller() {
+ return false;
+ }
+
+ @Override
+ public final long getTimeDeltaMs() {
+ return Integer.toUnsignedLong(mTimeDelta);
+ }
+ }
+
+ // circular buffer of log entries
+ private final Log[] mLog;
+ private int mLogSize;
+ private int mLogEndIndex;
+ private int mModificationCount;
+
+ // invalid if log is empty
+ private long mStartRealtimeMs;
+ private long mLastLogRealtimeMs;
+
+ public LocalEventLog(int size) {
+ mLog = new Log[size];
+ mLogSize = 0;
+ mLogEndIndex = 0;
+ mModificationCount = 0;
+
+ mStartRealtimeMs = -1;
+ mLastLogRealtimeMs = -1;
+ }
+
+ /**
+ * Should be overridden by subclasses to return a new immutable log event for the given
+ * arguments (as passed into {@link #addLogEvent(int, Object...)}.
+ */
+ protected abstract LogEvent createLogEvent(long timeDelta, int event, Object... args);
+
+ /**
+ * May be optionally overridden by subclasses if they wish to change how log event time is
+ * formatted.
+ */
+ protected String getTimePrefix(long timeMs) {
+ return TimeUtils.logTimeOfDay(timeMs) + ": ";
+ }
+
+ /**
+ * Call to add a new log event at the current time. The arguments provided here will be passed
+ * into {@link #createLogEvent(long, int, Object...)} in addition to a time delta, and should be
+ * used to construct an appropriate {@link LogEvent} object.
+ */
+ public void addLogEvent(int event, Object... args) {
+ long timeMs = SystemClock.elapsedRealtime();
+
+ // calculate delta
+ long delta = 0;
+ if (!isEmpty()) {
+ delta = timeMs - mLastLogRealtimeMs;
+
+ // if the delta is invalid, or if the delta is great enough using filler elements would
+ // result in an empty log anyways, just clear the log and continue, otherwise insert
+ // filler elements until we have a reasonable delta
+ if (delta < 0 || (delta / FillerEvent.MAX_TIME_DELTA) >= mLog.length - 1) {
+ clear();
+ delta = 0;
+ } else {
+ while (delta >= LogEvent.MAX_TIME_DELTA) {
+ long timeDelta = Math.min(FillerEvent.MAX_TIME_DELTA, delta);
+ addLogEventInternal(new FillerEvent(timeDelta));
+ delta -= timeDelta;
+ }
+ }
+ }
+
+ // for first log entry, set initial times
+ if (isEmpty()) {
+ mStartRealtimeMs = timeMs;
+ mLastLogRealtimeMs = mStartRealtimeMs;
+ }
+
+ addLogEventInternal(createLogEvent(delta, event, args));
+ }
+
+ private void addLogEventInternal(Log event) {
+ Preconditions.checkState(mStartRealtimeMs != -1 && mLastLogRealtimeMs != -1);
+
+ if (mLogSize == mLog.length) {
+ // if log is full, size will remain the same, but update the start time
+ mStartRealtimeMs += event.getTimeDeltaMs();
+ } else {
+ // otherwise add an item
+ mLogSize++;
+ }
+
+ // set log and increment end index
+ mLog[mLogEndIndex] = event;
+ mLogEndIndex = incrementIndex(mLogEndIndex);
+ mLastLogRealtimeMs = mLastLogRealtimeMs + event.getTimeDeltaMs();
+
+ mModificationCount++;
+ }
+
+ /** Clears the log of all entries. */
+ public void clear() {
+ mLogEndIndex = 0;
+ mLogSize = 0;
+ mModificationCount++;
+
+ mStartRealtimeMs = -1;
+ mLastLogRealtimeMs = -1;
+ }
+
+ // checks if the log is empty (if empty, times are invalid)
+ private boolean isEmpty() {
+ return mLogSize == 0;
+ }
+
+ @Override
+ public ListIterator<String> iterator() {
+ return new LogIterator();
+ }
+
+ // returns the index of the first element
+ private int startIndex() {
+ return wrapIndex(mLogEndIndex - mLogSize);
+ }
+
+ // returns the index after this one
+ private int incrementIndex(int index) {
+ return wrapIndex(index + 1);
+ }
+
+ // returns the index before this one
+ private int decrementIndex(int index) {
+ return wrapIndex(index - 1);
+ }
+
+ // rolls over the given index if necessary
+ private int wrapIndex(int index) {
+ // java modulo will keep negative sign, we need to rollover
+ return (index % mLog.length + mLog.length) % mLog.length;
+ }
+
+ private class LogIterator implements ListIterator<String> {
+
+ private final int mModificationGuard;
+
+ private final long mSystemTimeDeltaMs;
+
+ private long mCurrentRealtimeMs;
+ private int mIndex;
+ private int mCount;
+
+ LogIterator() {
+ mModificationGuard = mModificationCount;
+ mSystemTimeDeltaMs = System.currentTimeMillis() - SystemClock.elapsedRealtime();
+ mCurrentRealtimeMs = mStartRealtimeMs;
+ mIndex = startIndex();
+ mCount = 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return mCount < mLogSize;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return mCount > 0;
+ }
+
+ @Override
+ // return then increment
+ public String next() {
+ checkModifications();
+
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Log log = mLog[mIndex];
+ long nextDeltaMs = log.getTimeDeltaMs();
+ long realtimeMs = mCurrentRealtimeMs + nextDeltaMs;
+
+ // calculate next index, skipping filler events
+ do {
+ mCurrentRealtimeMs += nextDeltaMs;
+ mIndex = incrementIndex(mIndex);
+ if (++mCount < mLogSize) {
+ nextDeltaMs = mLog[mIndex].getTimeDeltaMs();
+ }
+ } while (mCount < mLogSize && mLog[mIndex].isFiller());
+
+ return getTimePrefix(realtimeMs + mSystemTimeDeltaMs) + log.getLogString();
+ }
+
+ @Override
+ // decrement then return
+ public String previous() {
+ checkModifications();
+
+ Log log;
+ long currentDeltaMs;
+ long realtimeMs;
+
+ // calculate previous index, skipping filler events with MAX_TIME_DELTA
+ do {
+ if (!hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+
+ mIndex = decrementIndex(mIndex);
+ mCount--;
+
+ log = mLog[mIndex];
+ realtimeMs = mCurrentRealtimeMs;
+
+ if (mCount > 0) {
+ currentDeltaMs = log.getTimeDeltaMs();
+ mCurrentRealtimeMs -= currentDeltaMs;
+ }
+ } while (mCount >= 0 && log.isFiller());
+
+ return getTimePrefix(realtimeMs + mSystemTimeDeltaMs) + log.getLogString();
+ }
+
+ private void checkModifications() {
+ if (mModificationGuard != mModificationCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ @Override
+ public int nextIndex() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int previousIndex() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void add(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void set(String s) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1cb610f..9868fc1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -116,6 +116,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -150,10 +151,7 @@
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
@@ -1133,16 +1131,14 @@
boolean scheduleTopResumedActivityChanged(boolean onTop) {
if (!attachedToProcess()) {
- if (DEBUG_STATES) {
- Slog.w(TAG, "Can't report activity position update - client not running"
- + ", activityRecord=" + this);
- }
+ ProtoLog.w(WM_DEBUG_STATES,
+ "Can't report activity position update - client not running, "
+ + "activityRecord=%s", this);
return false;
}
try {
- if (DEBUG_STATES) {
- Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop);
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Sending position change to %s, onTop: %b",
+ this, onTop);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
TopResumedActivityChangeItem.obtain(onTop));
@@ -1308,6 +1304,8 @@
return;
}
+ // TODO(b/169035022): move to a more-appropriate place.
+ mAtmService.getTransitionController().collect(this);
if (prevDc.mOpeningApps.remove(this)) {
// Transfer opening transition to new display.
mDisplayContent.mOpeningApps.add(this);
@@ -2516,10 +2514,8 @@
*/
@FinishRequest int finishIfPossible(int resultCode, Intent resultData,
NeededUriGrants resultGrants, String reason, boolean oomAdj) {
- if (DEBUG_RESULTS || DEBUG_STATES) {
- Slog.v(TAG_STATES, "Finishing activity r=" + this + ", result=" + resultCode
- + ", data=" + resultData + ", reason=" + reason);
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Finishing activity r=%s, result=%d, data=%s, "
+ + "reason=%s", this, resultCode, resultData, reason);
if (finishing) {
Slog.w(TAG, "Duplicate finish request for r=" + this);
@@ -2601,7 +2597,7 @@
setVisibility(false);
if (stack.mPausingActivity == null) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + this);
+ ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this);
if (DEBUG_USER_LEAVING) {
Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
}
@@ -2648,7 +2644,7 @@
}
return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
} else {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this);
+ ProtoLog.v(WM_DEBUG_STATES, "Finish waiting for pause of: %s", this);
}
return FINISH_RESULT_REQUESTED;
@@ -2700,7 +2696,7 @@
// activities be updated, they may be seen by users.
ensureVisibility = true;
} else if (mStackSupervisor.getKeyguardController().isKeyguardLocked()
- && stack.topActivityOccludesKeyguard()) {
+ && mStackSupervisor.getKeyguardController().topActivityOccludesKeyguard(this)) {
// Ensure activity visibilities and update lockscreen occluded/dismiss state when
// finishing the top activity that occluded keyguard. So that, the
// ActivityStack#mTopActivityOccludesKeyguard can be updated and the activity below
@@ -2805,7 +2801,7 @@
*/
@VisibleForTesting
boolean addToFinishingAndWaitForIdle() {
- if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this);
+ ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending finish: %s", this);
setState(FINISHING, "addToFinishingAndWaitForIdle");
if (!mStackSupervisor.mFinishingActivities.contains(this)) {
mStackSupervisor.mFinishingActivities.add(this);
@@ -2833,10 +2829,8 @@
}
if (isState(DESTROYING, DESTROYED)) {
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "activity " + this + " already destroying."
- + "skipping request with reason:" + reason);
- }
+ ProtoLog.v(WM_DEBUG_STATES, "activity %s already destroying, skipping "
+ + "request with reason:%s", this, reason);
return false;
}
@@ -2877,16 +2871,13 @@
// the list yet. Otherwise, we can just immediately put it in the destroyed state since
// we are not removing it from the list.
if (finishing && !skipDestroy) {
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to DESTROYING: " + this + " (destroy requested)");
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYING: %s (destroy requested)", this);
setState(DESTROYING,
"destroyActivityLocked. finishing and not skipping destroy");
mAtmService.mH.postDelayed(mDestroyTimeoutRunnable, DESTROY_TIMEOUT);
} else {
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (destroy skipped)");
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s "
+ + "(destroy skipped)", this);
setState(DESTROYED,
"destroyActivityLocked. not finishing or skipping destroy");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this);
@@ -2898,7 +2889,7 @@
removeFromHistory(reason + " hadNoApp");
removedFromHistory = true;
} else {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (no app)");
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (no app)", this);
setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
}
}
@@ -2933,9 +2924,8 @@
takeFromHistory();
removeTimeouts();
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (removed from history)");
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (removed from history)",
+ this);
setState(DESTROYED, "removeFromHistory");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
detachFromProcess();
@@ -3234,6 +3224,8 @@
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
waitingToShow = false;
+ // TODO(b/169035022): move to a more-appropriate place.
+ mAtmService.getTransitionController().collect(this);
// Defer removal of this activity when either a child is animating, or app transition is on
// going. App transition animation might be applied on the parent stack not on the activity,
// but the actual frame buffer is associated with the activity, so we have to keep the
@@ -3245,6 +3237,8 @@
} else if (getDisplayContent().mAppTransition.isTransitionSet()) {
getDisplayContent().mClosingApps.add(this);
delayed = true;
+ } else if (mAtmService.getTransitionController().inTransition()) {
+ delayed = true;
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
@@ -4076,6 +4070,11 @@
return mVisible;
}
+ @Override
+ boolean isVisibleRequested() {
+ return mVisibleRequested;
+ }
+
void setVisible(boolean visible) {
if (visible != mVisible) {
mVisible = visible;
@@ -4206,6 +4205,11 @@
transferStartingWindowFromHiddenAboveTokenIfNeeded();
}
+ // TODO(b/169035022): move to a more-appropriate place.
+ mAtmService.getTransitionController().collect(this);
+ if (!visible && mAtmService.getTransitionController().inTransition()) {
+ return;
+ }
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
// Note that we ignore display frozen since we want the opening / closing transition type
@@ -4439,12 +4443,12 @@
}
void setState(ActivityState state, String reason) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
- + " to:" + state + " reason:" + reason);
+ ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s",
+ this, getState(), state, reason);
if (state == mState) {
// No need to do anything if state doesn't change.
- if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state);
+ ProtoLog.v(WM_DEBUG_STATES, "State unchanged from:%s", state);
return;
}
@@ -4631,15 +4635,9 @@
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
}
- private void updateVisibleIgnoringKeyguard(boolean behindFullscreenActivity) {
- // Check whether activity should be visible without Keyguard influence
- visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
- && okToShowLocked();
- }
-
/** @return {@code true} if this activity should be made visible. */
private boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) {
- updateVisibleIgnoringKeyguard(behindFullscreenActivity);
+ updateVisibilityIgnoringKeyguard(behindFullscreenActivity);
if (ignoringKeyguard) {
return visibleIgnoringKeyguard;
@@ -4673,20 +4671,9 @@
return mStackSupervisor.getKeyguardController().checkKeyguardVisibility(this);
}
- void updateVisibility(boolean behindFullscreenActivity) {
- updateVisibleIgnoringKeyguard(behindFullscreenActivity);
- final Task task = getRootTask();
- if (task == null || !visibleIgnoringKeyguard) {
- return;
- }
- // Now check whether it's really visible depending on Keyguard state, and update
- // {@link ActivityStack} internal states.
- // Inform the method if this activity is the top activity of this stack, but exclude the
- // case where this is the top activity in a pinned stack.
- final boolean isTop = this == task.getTopNonFinishingActivity();
- final boolean isTopNotPinnedStack = task.isAttached()
- && task.getDisplayArea().isTopNotFinishNotPinnedStack(task);
- task.updateKeyguardVisibility(this, isTop && isTopNotPinnedStack);
+ void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
+ visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
+ && okToShowLocked();
}
boolean shouldBeVisible() {
@@ -4944,7 +4931,7 @@
static void activityResumedLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
+ ProtoLog.i(WM_DEBUG_STATES, "Resumed activity; dropping state of: %s", r);
if (r == null) {
// If an app reports resumed after a long delay, the record on server side might have
// been removed (e.g. destroy timeout), so the token could be null.
@@ -5015,8 +5002,8 @@
}
void activityPaused(boolean timeout) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
- "Activity paused: token=" + appToken + ", timeout=" + timeout);
+ ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", appToken,
+ timeout);
final Task stack = getStack();
@@ -5024,8 +5011,8 @@
removePauseTimeout();
if (stack.mPausingActivity == this) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + this
- + (timeout ? " (due to timeout)" : " (pause complete)"));
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
+ (timeout ? "(due to timeout)" : " (pause complete)"));
mAtmService.deferWindowLayout();
try {
stack.completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
@@ -5040,8 +5027,8 @@
if (isState(PAUSING)) {
setState(PAUSED, "activityPausedLocked");
if (finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG,
- "Executing finish of failed to pause activity: " + this);
+ ProtoLog.v(WM_DEBUG_STATES,
+ "Executing finish of failed to pause activity: %s", this);
completeFinishing("activityPausedLocked");
}
}
@@ -5058,7 +5045,7 @@
void schedulePauseTimeout() {
pauseTime = SystemClock.uptimeMillis();
mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT);
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
+ ProtoLog.v(WM_DEBUG_STATES, "Waiting for pause to complete...");
}
private void removePauseTimeout() {
@@ -5087,17 +5074,15 @@
if (isNoHistory()) {
if (!finishing) {
if (!stack.shouldSleepActivities()) {
- if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + this);
+ ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this);
if (finishIfPossible("stop-no-history", false /* oomAdj */)
!= FINISH_RESULT_CANCELLED) {
resumeKeyDispatchingLocked();
return;
}
} else {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "Not finishing noHistory " + this
- + " on stop because we're just sleeping");
- }
+ ProtoLog.d(WM_DEBUG_STATES, "Not finishing noHistory %s on stop "
+ + "because we're just sleeping", this);
}
}
}
@@ -5108,9 +5093,8 @@
resumeKeyDispatchingLocked();
try {
stopped = false;
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (stop requested)");
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
+
setState(STOPPING, "stopIfPossible");
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "Stopping:" + this);
@@ -5130,7 +5114,7 @@
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
stopped = true;
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this);
+ ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
setState(STOPPED, "stopIfPossible");
if (deferRelaunchUntilPaused) {
destroyImmediately("stop-except");
@@ -5159,9 +5143,9 @@
launchCount = 0;
updateTaskDescription(description);
}
- if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + mIcicle);
+ ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle);
if (!stopped) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this);
removeStopTimeout();
stopped = true;
if (isStopping) {
@@ -5197,10 +5181,9 @@
boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
|| (isRootOfTask() && stack.getChildCount() <= 1);
if (scheduleIdle || forceIdle) {
- if (DEBUG_PAUSE) {
- Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle=" + forceIdle
- + "immediate=" + !idleDelayed);
- }
+ ProtoLog.v(WM_DEBUG_STATES,
+ "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
+
if (!idleDelayed) {
mStackSupervisor.scheduleIdle();
} else {
@@ -7127,9 +7110,9 @@
} else {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
this);
- if (DEBUG_STATES && !mVisibleRequested) {
- Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
- + " called by " + Debug.getCallers(4));
+ if (!mVisibleRequested) {
+ ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
+ + "activity %s called by %s", this, Debug.getCallers(4));
}
relaunchActivityLocked(preserveWindow);
}
@@ -7262,9 +7245,8 @@
startFreezingScreenLocked(0);
try {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
- "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this
- + " callers=" + Debug.getCallers(6));
+ ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
+ (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
forceNewConfig = false;
startRelaunching();
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
@@ -7287,13 +7269,11 @@
// request resume if this activity is currently resumed, which implies we aren't
// sleeping.
} catch (RemoteException e) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
+ ProtoLog.i(WM_DEBUG_STATES, "Relaunch failed %s", e);
}
if (andResume) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "Resumed after relaunch " + this);
- }
+ ProtoLog.d(WM_DEBUG_STATES, "Resumed after relaunch %s", this);
results = null;
newIntents = null;
mAtmService.getAppWarningsLocked().onResumeActivity(this);
@@ -7865,6 +7845,7 @@
final Rect insets = new Rect();
mainWindow.getContentInsets(insets);
InsetUtils.addInsets(insets, getLetterboxInsets());
+
return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
record.mAdapter.mCapturedLeash, !fillsParent(),
new Rect(), insets,
@@ -7872,7 +7853,7 @@
record.mAdapter.mStackBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
- record.mStartBounds);
+ record.mStartBounds, task.getPictureInPictureParams());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index f7fd6ec..e2c1303 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -44,15 +44,14 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
@@ -66,7 +65,6 @@
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
-import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
@@ -135,6 +133,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.TransferPipe;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -721,9 +720,9 @@
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in
// the paused state because they will first be resumed then paused on the client side.
- if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
- "realStartActivityLocked: Skipping start of r=" + r
- + " some activities pausing...");
+ ProtoLog.v(WM_DEBUG_STATES,
+ "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+ r);
return false;
}
@@ -919,8 +918,8 @@
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
- if (DEBUG_STATES) Slog.v(TAG_STATES,
- "Moving to PAUSED: " + r + " (starting in paused state)");
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s "
+ + "(starting in paused state)", r);
r.setState(PAUSED, "realStartActivityLocked");
mRootWindowContainer.executeAppTransitionForAllDisplay();
}
@@ -1071,11 +1070,11 @@
/** Check if caller is allowed to launch activities on specified display. */
boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId,
ActivityInfo aInfo) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
- + " callingPid=" + callingPid + " callingUid=" + callingUid);
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: displayId=%d callingPid=%d "
+ + "callingUid=%d", launchDisplayId, callingPid, callingUid);
if (callingPid == -1 && callingUid == -1) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: no caller info, skip check");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: no caller info, skip check");
return true;
}
@@ -1091,8 +1090,7 @@
final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid,
callingUid);
if (startAnyPerm == PERMISSION_GRANTED) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " allow launch any on display");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch any on display");
return true;
}
@@ -1104,36 +1102,36 @@
// Limit launching on untrusted displays because their contents can be read from Surface
// by apps that created them.
if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " disallow launch on virtual display for not-embedded activity.");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: disallow launch on "
+ + "virtual display for not-embedded activity.");
return false;
}
// Check if the caller is allowed to embed activities from other apps.
if (mService.checkPermission(ACTIVITY_EMBEDDING, callingPid, callingUid)
== PERMISSION_DENIED && !uidPresentOnDisplay) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " disallow activity embedding without permission.");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: disallow activity "
+ + "embedding without permission.");
return false;
}
}
if (!displayContent.isPrivate()) {
// Anyone can launch on a public display.
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " allow launch on public display");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch on public "
+ + "display");
return true;
}
// Check if the caller is the owner of the display.
if (display.getOwnerUid() == callingUid) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " allow launch for owner of the display");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch for owner of the"
+ + " display");
return true;
}
if (uidPresentOnDisplay) {
- if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
- + " allow launch for caller present on the display");
+ ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch for caller "
+ + "present on the display");
return true;
}
@@ -1830,9 +1828,10 @@
for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
final ActivityRecord s = mStoppingActivities.get(i);
final boolean animating = s.isAnimating(TRANSITION | PARENTS,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
- if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible
- + " animating=" + animating + " finishing=" + s.finishing);
+ ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)
+ || mService.getTransitionController().inTransition(s);
+ ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ + "finishing=%s", s, s.nowVisible, animating, s.finishing);
if (!animating || mService.mShuttingDown) {
if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
@@ -1842,7 +1841,7 @@
continue;
}
- if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+ ProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);
if (readyToStopActivities == null) {
readyToStopActivities = new ArrayList<>();
}
@@ -2076,7 +2075,7 @@
msg.obj = r;
r.topResumedStateLossTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, TOP_RESUMED_STATE_LOSS_TIMEOUT);
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Waiting for top state to be released by " + r);
+ ProtoLog.v(WM_DEBUG_STATES, "Waiting for top state to be released by %s", r);
}
/**
@@ -2084,10 +2083,9 @@
* activity if needed.
*/
void handleTopResumedStateReleased(boolean timeout) {
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Top resumed state released "
- + (timeout ? " (due to timeout)" : " (transition complete)"));
- }
+ ProtoLog.v(WM_DEBUG_STATES, "Top resumed state released %s",
+ (timeout ? "(due to timeout)" : "(transition complete)"));
+
mHandler.removeMessages(TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG);
if (!mTopResumedActivityWaitingForPrev) {
// Top resumed activity state loss already handled.
@@ -2304,18 +2302,14 @@
/** Starts a batch of visibility updates. */
void beginActivityVisibilityUpdate() {
+ if (mVisibilityTransactionDepth == 0) {
+ getKeyguardController().updateVisibility();
+ }
mVisibilityTransactionDepth++;
}
/** Ends a batch of visibility updates. */
- void endActivityVisibilityUpdate(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
- if (mVisibilityTransactionDepth == 1) {
- getKeyguardController().visibilitiesUpdated();
- // commit visibility to activities
- mRootWindowContainer.commitActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
- }
+ void endActivityVisibilityUpdate() {
mVisibilityTransactionDepth--;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index fa4373f..28e71fa 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -57,14 +57,13 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
@@ -1909,10 +1908,8 @@
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
if (!mMovedToFront && mDoResume) {
- if (DEBUG_TASKS) {
- Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
- + " from " + targetTaskTop);
- }
+ ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetStack,
+ targetTaskTop);
mTargetStack.moveToFront("intentActivityFound");
}
resumeTargetStackIfNeeded();
@@ -2564,10 +2561,8 @@
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
- if (DEBUG_TASKS) {
- Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in new task " + mStartActivity.getTask());
- }
+ ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
+ mStartActivity, mStartActivity.getTask());
if (taskToAffiliate != null) {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index 3c562a6..b5675a9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -43,14 +43,10 @@
// Enable all debug log categories for activities.
private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
- static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
public static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
- static final boolean DEBUG_TASKS = DEBUG_ALL || false;
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0402140..0938d22 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -70,6 +70,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -96,9 +97,7 @@
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
@@ -324,14 +323,14 @@
/** Hardware-reported OpenGLES version. */
final int GL_ES_VERSION;
- public static final String DUMP_ACTIVITIES_CMD = "activities" ;
- public static final String DUMP_ACTIVITIES_SHORT_CMD = "a" ;
- public static final String DUMP_LASTANR_CMD = "lastanr" ;
- public static final String DUMP_LASTANR_TRACES_CMD = "lastanr-traces" ;
- public static final String DUMP_STARTER_CMD = "starter" ;
- public static final String DUMP_CONTAINERS_CMD = "containers" ;
- public static final String DUMP_RECENTS_CMD = "recents" ;
- public static final String DUMP_RECENTS_SHORT_CMD = "r" ;
+ public static final String DUMP_ACTIVITIES_CMD = "activities";
+ public static final String DUMP_ACTIVITIES_SHORT_CMD = "a";
+ public static final String DUMP_LASTANR_CMD = "lastanr";
+ public static final String DUMP_LASTANR_TRACES_CMD = "lastanr-traces";
+ public static final String DUMP_STARTER_CMD = "starter";
+ public static final String DUMP_CONTAINERS_CMD = "containers";
+ public static final String DUMP_RECENTS_CMD = "recents";
+ public static final String DUMP_RECENTS_SHORT_CMD = "r";
/** This activity is not being relaunched, or being relaunched for a non-resize reason. */
public static final int RELAUNCH_REASON_NONE = 0;
@@ -614,7 +613,9 @@
LAYOUT_REASON_CONFIG_CHANGED,
LAYOUT_REASON_VISIBILITY_CHANGED,
})
- @interface LayoutReason {}
+ @interface LayoutReason {
+ }
+
static final int LAYOUT_REASON_CONFIG_CHANGED = 0x1;
static final int LAYOUT_REASON_VISIBILITY_CHANGED = 0x2;
@@ -653,7 +654,8 @@
*
* @see #updateResumedAppTrace
*/
- private @Nullable ActivityRecord mTracedResumedActivity;
+ @Nullable
+ private ActivityRecord mTracedResumedActivity;
/** If non-null, we are tracking the time the user spends in the currently focused app. */
AppTimeTracker mCurAppTimeTracker;
@@ -716,6 +718,7 @@
int OOM_ADJUSTMENT = 1;
int LRU_UPDATE = 2;
int PROCESS_CHANGE = 3;
+
int caller() default NONE;
}
@@ -873,7 +876,8 @@
}
protected ActivityStackSupervisor createStackSupervisor() {
- final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
+ final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this,
+ mH.getLooper());
supervisor.initialize();
return supervisor;
}
@@ -958,6 +962,10 @@
return mLockTaskController;
}
+ TransitionController getTransitionController() {
+ return mWindowOrganizerController.getTransitionController();
+ }
+
/**
* Return the global configuration used by the process corresponding to the input pid. This is
* usually the global configuration with some overrides specific to that process.
@@ -1124,7 +1132,7 @@
throw new IllegalArgumentException("Bad PendingIntent object");
}
- PendingIntentRecord pir = (PendingIntentRecord)target;
+ PendingIntentRecord pir = (PendingIntentRecord) target;
synchronized (mGlobalLock) {
// If this is coming from the currently resumed activity, it is
@@ -1177,14 +1185,14 @@
// Look for the original activity in the list...
final int N = resolves != null ? resolves.size() : 0;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
ResolveInfo rInfo = resolves.get(i);
if (rInfo.activityInfo.packageName.equals(r.packageName)
&& rInfo.activityInfo.name.equals(r.info.name)) {
// We found the current one... the next matching is
// after it.
i++;
- if (i<N) {
+ if (i < N) {
aInfo = resolves.get(i).activityInfo;
}
if (debug) {
@@ -1208,11 +1216,10 @@
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
- intent.setFlags(intent.getFlags()&~(
- Intent.FLAG_ACTIVITY_FORWARD_RESULT|
- Intent.FLAG_ACTIVITY_CLEAR_TOP|
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
- FLAG_ACTIVITY_NEW_TASK));
+ intent.setFlags(intent.getFlags() & ~(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ | FLAG_ACTIVITY_NEW_TASK));
// Okay now we need to start the new activity, replacing the currently running activity.
// This is a little tricky because we want to start the new one as if the current one is
@@ -1577,11 +1584,12 @@
/**
* Start the recents activity to perform the recents animation.
*
- * @param intent The intent to start the recents activity.
+ * @param intent The intent to start the recents activity.
+ * @param eventTime When the (touch) event is triggered to start recents activity.
* @param recentsAnimationRunner Pass {@code null} to only preload the activity.
*/
@Override
- public void startRecentsActivity(Intent intent, @Deprecated IAssistDataReceiver unused,
+ public void startRecentsActivity(Intent intent, long eventTime,
@Nullable IRecentsAnimationRunner recentsAnimationRunner) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
final int callingPid = Binder.getCallingPid();
@@ -1601,7 +1609,7 @@
if (recentsAnimationRunner == null) {
anim.preloadRecentsActivity();
} else {
- anim.startRecentsActivity(recentsAnimationRunner);
+ anim.startRecentsActivity(recentsAnimationRunner, eventTime);
}
}
} finally {
@@ -1633,12 +1641,12 @@
*
* If the target display is private or virtual, some restrictions will apply.
*
- * @param displayId Target display id.
- * @param intent Intent used to launch the activity.
+ * @param displayId Target display id.
+ * @param intent Intent used to launch the activity.
* @param resolvedType The MIME type of the intent.
- * @param userId The id of the user for whom the call is made.
+ * @param userId The id of the user for whom the call is made.
* @return {@code true} if a call to start an activity on the target display should succeed and
- * no {@link SecurityException} will be thrown, {@code false} otherwise.
+ * no {@link SecurityException} will be thrown, {@code false} otherwise.
*/
@Override
public final boolean isActivityStartAllowedOnDisplay(int displayId, Intent intent,
@@ -1667,11 +1675,10 @@
/**
* This is the internal entry point for handling Activity.finish().
*
- * @param token The Binder token referencing the Activity we want to finish.
+ * @param token The Binder token referencing the Activity we want to finish.
* @param resultCode Result code, if any, from this Activity.
* @param resultData Result data (Intent), if any, from this Activity.
* @param finishTask Whether to finish the task associated with this Activity.
- *
* @return Returns true if the activity successfully finished, or false if it is still running.
*/
@Override
@@ -2306,14 +2313,14 @@
* There are several possible results of this call:
* - if the task is locked, then we will show the lock toast
* - if there is a task behind the provided task, then that task is made visible and resumed as
- * this task is moved to the back
+ * this task is moved to the back
* - otherwise, if there are no other tasks in the stack:
- * - if this task is in the pinned stack, then we remove the stack completely, which will
- * have the effect of moving the task to the top or bottom of the fullscreen stack
- * (depending on whether it is visible)
- * - otherwise, we simply return home and hide this task
+ * - if this task is in the pinned stack, then we remove the stack completely, which will
+ * have the effect of moving the task to the top or bottom of the fullscreen stack
+ * (depending on whether it is visible)
+ * - otherwise, we simply return home and hide this task
*
- * @param token A reference to the activity we wish to move
+ * @param token A reference to the activity we wish to move
* @param nonRoot If false then this only works if the activity is the root
* of a task; if true it will work for any activity in a task.
* @return Returns true if the move completed, false if not.
@@ -2394,8 +2401,8 @@
return false;
}
- if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
- + " to windowingMode=" + windowingMode + " toTop=" + toTop);
+ ProtoLog.d(WM_DEBUG_TASKS, "setTaskWindowingMode: moving task=%d "
+ + "to windowingMode=%d toTop=%b", taskId, windowingMode, toTop);
if (!task.isActivityTypeStandardOrUndefined()) {
throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
@@ -2458,7 +2465,8 @@
@Override
public void unhandledBack() {
- mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
+ "unhandledBack()");
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
@@ -2505,9 +2513,10 @@
@Override
public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
int flags, Bundle bOptions) {
- mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
+ mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
+ "moveTaskToFront()");
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
+ ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToFront: moving taskId=%d", taskId);
synchronized (mGlobalLock) {
moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
SafeActivityOptions.fromBundle(bOptions));
@@ -2539,7 +2548,7 @@
try {
final Task task = mRootWindowContainer.anyTaskForId(taskId);
if (task == null) {
- Slog.d(TAG, "Could not find task for id: "+ taskId);
+ ProtoLog.d(WM_DEBUG_TASKS, "Could not find task for id: %d", taskId);
SafeActivityOptions.abort(options);
return;
}
@@ -2752,8 +2761,8 @@
return;
}
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
- + " to stackId=" + stackId + " toTop=" + toTop);
+ ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToStack: moving task=%d to "
+ + "stackId=%d toTop=%b", taskId, stackId, toTop);
final Task stack = mRootWindowContainer.getStack(stackId);
if (stack == null) {
@@ -2776,7 +2785,7 @@
* Moves the specified task to the primary-split-screen stack.
*
* @param taskId Id of task to move.
- * @param toTop If the task and stack should be moved to the top.
+ * @param toTop If the task and stack should be moved to the top.
* @return Whether the task was successfully put into splitscreen.
*/
@Override
@@ -3289,8 +3298,8 @@
if (intent.getSourceBounds() != null) {
intent.setSourceBounds(null);
}
- if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
- if ((intent.getFlags()&Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) == 0) {
+ if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
+ if ((intent.getFlags() & Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) == 0) {
// The caller has added this as an auto-remove task... that makes no
// sense, so turn off auto-remove.
intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
@@ -3488,8 +3497,8 @@
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
- + " to displayId=" + displayId);
+ ProtoLog.d(WM_DEBUG_TASKS, "moveStackToDisplay: moving stackId=%d to "
+ + "displayId=%d", stackId, displayId);
mRootWindowContainer.moveStackToDisplay(stackId, displayId, ON_TOP);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3648,14 +3657,16 @@
try {
if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
allowed = true;
- if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
- + " is using old GET_TASKS but privileged; allowing");
+ ProtoLog.w(WM_DEBUG_TASKS,
+ "%s: caller %d is using old GET_TASKS but privileged; allowing",
+ caller, callingUid);
}
} catch (RemoteException e) {
}
}
- if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
- + " does not hold REAL_GET_TASKS; limiting output");
+ ProtoLog.w(WM_DEBUG_TASKS,
+ "%s: caller %d does not hold REAL_GET_TASKS; limiting output", caller,
+ callingUid);
}
return allowed;
}
@@ -3974,7 +3985,8 @@
@Override
public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
- mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
+ "suppressResizeConfigChanges()");
synchronized (mGlobalLock) {
mSuppressResizeConfigChanges = suppress;
}
@@ -3984,10 +3996,9 @@
* Moves the top activity in the input stackId to the pinned stack.
*
* @param stackId Id of stack to move the top activity to pinned stack.
- * @param bounds Bounds to use for pinned stack.
- *
+ * @param bounds Bounds to use for pinned stack.
* @return True if the top activity of the input stack was successfully moved to the pinned
- * stack.
+ * stack.
*/
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
@@ -4142,7 +4153,7 @@
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(
- r.mDisplayContent, params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
@@ -4190,8 +4201,8 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect primaryRect =
tempDockedTaskInsetBounds != null ? tempDockedTaskInsetBounds
- : (tempDockedTaskBounds != null ? tempDockedTaskBounds
- : dockedBounds);
+ : (tempDockedTaskBounds != null ? tempDockedTaskBounds
+ : dockedBounds);
wct.setBounds(primary.mRemoteToken.toWindowContainerToken(), primaryRect);
Rect otherRect = tempOtherTaskInsetBounds != null ? tempOtherTaskInsetBounds
: tempOtherTaskBounds;
@@ -4460,7 +4471,8 @@
public void updateLockTaskFeatures(int userId, int flags) {
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != SYSTEM_UID) {
- mAmInternal.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+ mAmInternal.enforceCallingPermission(
+ android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
"updateLockTaskFeatures()");
}
synchronized (mGlobalLock) {
@@ -4764,11 +4776,12 @@
/**
* Clears launch params for the given package.
+ *
* @param packageNames the names of the packages of which the launch params are to be cleared
*/
@Override
public void clearLaunchParamsForPackages(List<String> packageNames) {
- mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
"clearLaunchParamsForPackages");
synchronized (mGlobalLock) {
for (int i = 0; i < packageNames.size(); ++i) {
@@ -4783,7 +4796,7 @@
*/
@Override
public void setDisplayToSingleTaskInstance(int displayId) {
- mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
"setDisplayToSingleTaskInstance");
final long origId = Binder.clearCallingIdentity();
try {
@@ -4802,7 +4815,7 @@
*/
@Override
public void requestPictureInPictureMode(IBinder token) throws RemoteException {
- mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
"requestPictureInPictureMode");
final long origId = Binder.clearCallingIdentity();
try {
@@ -4898,7 +4911,7 @@
boolean needSep = printedAnything;
boolean printed = ActivityStackSupervisor.printThisActivity(pw,
- mRootWindowContainer.getTopResumedActivity(), dumpPackage, needSep,
+ mRootWindowContainer.getTopResumedActivity(), dumpPackage, needSep,
" ResumedActivity: ", null);
if (printed) {
printedAnything = true;
@@ -4932,19 +4945,20 @@
/**
* There are three things that cmd can be:
- * - a flattened component name that matches an existing activity
- * - the cmd arg isn't the flattened component name of an existing activity:
- * dump all activity whose component contains the cmd as a substring
- * - A hex number of the ActivityRecord object instance.
+ * - a flattened component name that matches an existing activity
+ * - the cmd arg isn't the flattened component name of an existing activity:
+ * dump all activity whose component contains the cmd as a substring
+ * - A hex number of the ActivityRecord object instance.
* <p>
* The caller should not hold lock when calling this method because it will wait for the
* activities to complete the dump.
*
- * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
- * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
+ * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
+ * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
- int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
+ int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
+ boolean dumpFocusedStackOnly) {
ArrayList<ActivityRecord> activities;
synchronized (mGlobalLock) {
@@ -4971,9 +4985,12 @@
final Task task = r.getTask();
if (lastTask != task) {
lastTask = task;
- pw.print("TASK "); pw.print(lastTask.affinity);
- pw.print(" id="); pw.print(lastTask.mTaskId);
- pw.print(" userId="); pw.println(lastTask.mUserId);
+ pw.print("TASK ");
+ pw.print(lastTask.affinity);
+ pw.print(" id=");
+ pw.print(lastTask.mTaskId);
+ pw.print(" userId=");
+ pw.println(lastTask.mUserId);
if (dumpAll) {
lastTask.dump(pw, " ");
}
@@ -4993,8 +5010,11 @@
String innerPrefix = prefix + " ";
IApplicationThread appThread = null;
synchronized (mGlobalLock) {
- pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
- pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
+ pw.print(prefix);
+ pw.print("ACTIVITY ");
+ pw.print(r.shortComponentName);
+ pw.print(" ");
+ pw.print(Integer.toHexString(System.identityHashCode(r)));
pw.print(" pid=");
if (r.hasProcess()) {
pw.println(r.app.getPid());
@@ -5053,7 +5073,7 @@
public Configuration getConfiguration() {
Configuration ci;
- synchronized(mGlobalLock) {
+ synchronized (mGlobalLock) {
ci = new Configuration(getGlobalConfigurationForCallingPid());
ci.userSetLocale = false;
}
@@ -5898,7 +5918,7 @@
final IBinder threadBinder = thread.asBinder();
final ArrayMap<String, SparseArray<WindowProcessController>> pmap = mProcessNames.getMap();
- for (int i = pmap.size()-1; i >= 0; i--) {
+ for (int i = pmap.size() - 1; i >= 0; i--) {
final SparseArray<WindowProcessController> procs = pmap.valueAt(i);
for (int j = procs.size() - 1; j >= 0; j--) {
final WindowProcessController proc = procs.valueAt(j);
@@ -5963,7 +5983,7 @@
TimeMigrationUtils.formatMillisWithFixedFormat(System.currentTimeMillis());
sb.append(timeString);
sb.append(": ");
- TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
+ TimeUtils.formatDuration(SystemClock.uptimeMillis() - startTime, sb);
sb.append(" since ");
sb.append(msg);
FileOutputStream fos = new FileOutputStream(tracesFile);
@@ -5986,7 +6006,7 @@
File lastTracesFile = null;
File curTracesFile = null;
- for (int i=9; i>=0; i--) {
+ for (int i = 9; i >= 0; i--) {
String name = String.format(Locale.US, "slow%02d.txt", i);
curTracesFile = new File(tracesDir, name);
if (curTracesFile.exists()) {
@@ -6033,7 +6053,8 @@
case REPORT_TIME_TRACKER_MSG: {
AppTimeTracker tracker = (AppTimeTracker) msg.obj;
tracker.deliverResult(mContext);
- } break;
+ }
+ break;
}
}
}
@@ -6229,7 +6250,7 @@
*/
@Override
public void setVr2dDisplayId(int vr2dDisplayId) {
- if (DEBUG_STACK) Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId);
+ ProtoLog.d(WM_DEBUG_TASKS, "setVr2dDisplayId called for: %d", vr2dDisplayId);
synchronized (mGlobalLock) {
mVr2dDisplayId = vr2dDisplayId;
}
@@ -6537,7 +6558,7 @@
* Set the corresponding display information for the process global configuration. To be
* called when we need to show IME on a different display.
*
- * @param pid The process id associated with the IME window.
+ * @param pid The process id associated with the IME window.
* @param displayId The ID of the display showing the IME.
*/
@Override
@@ -6549,7 +6570,7 @@
if (pid == MY_PID || pid < 0) {
ProtoLog.w(WM_DEBUG_CONFIGURATION,
- "Trying to update display configuration for system/invalid process.");
+ "Trying to update display configuration for system/invalid process.");
return;
}
synchronized (mGlobalLock) {
@@ -6939,7 +6960,8 @@
pw.println();
getActivityStartController().dump(pw, " ", null);
pw.println();
- pw.println("-------------------------------------------------------------------------------");
+ pw.println("-------------------------------------------------------------------"
+ + "------------");
dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
"" /* header */);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index f76108f..0e47ea8 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2214,6 +2214,10 @@
*/
boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
@TransitionFlags int flags, boolean forceOverride) {
+ if (mService.mAtmService.getTransitionController().adaptLegacyPrepare(
+ transit, flags, forceOverride)) {
+ return false;
+ }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d "
+ "Callers=%s",
@@ -2255,7 +2259,7 @@
|| transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
}
- private static boolean isKeyguardTransit(int transit) {
+ static boolean isKeyguardTransit(int transit) {
return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
|| transit == TRANSIT_KEYGUARD_UNOCCLUDE;
}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaGroup.java b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
new file mode 100644
index 0000000..bcf8c7c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
@@ -0,0 +1,57 @@
+/*
+ * 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.wm;
+
+import static android.content.pm.ActivityInfo.reverseOrientation;
+
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+
+/** The root of a partition of the logical display. */
+class DisplayAreaGroup extends RootDisplayArea {
+
+ DisplayAreaGroup(WindowManagerService wms, String name, int featureId) {
+ super(wms, name, featureId);
+ }
+
+ @Override
+ boolean isOrientationDifferentFromDisplay() {
+ if (mDisplayContent == null) {
+ return false;
+ }
+
+ final Rect bounds = getBounds();
+ final Rect displayBounds = mDisplayContent.getBounds();
+
+ return (bounds.width() < bounds.height())
+ != (displayBounds.width() < displayBounds.height());
+ }
+
+ @ActivityInfo.ScreenOrientation
+ @Override
+ int getOrientation(int candidate) {
+ int orientation = super.getOrientation(candidate);
+
+ // Reverse the requested orientation if the orientation of this DAG is different from the
+ // display, so that when the display rotates to the reversed orientation, this DAG will be
+ // in the requested orientation, so as the requested app.
+ // For example, if the display is 1200x900 (landscape), and this DAG is 600x900 (portrait).
+ // When an app below this DAG is requesting landscape, it should actually request the
+ // display to be portrait, so that the DAG and the app will be in landscape.
+ return isOrientationDifferentFromDisplay() ? reverseOrientation(orientation) : orientation;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1153c46..22b446d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1465,6 +1465,15 @@
// intermediate orientation change, it is more stable to freeze the display.
return false;
}
+ if (r.isState(RESUMED) && !r.getRootTask().mInResumeTopActivity) {
+ // If the activity is executing or has done the lifecycle callback, use normal
+ // rotation animation so the display info can be updated immediately (see
+ // updateDisplayAndOrientation). This prevents a compatibility issue such as
+ // calling setRequestedOrientation in Activity#onCreate and then get display info.
+ // If fixed rotation is applied, the display rotation will still be the old one,
+ // unless the client side gets the rotation again after the adjustments arrive.
+ return false;
+ }
} else if (r != topRunningActivity()) {
// If the transition has not started yet, the activity must be the top.
return false;
@@ -2273,6 +2282,11 @@
}
@Override
+ boolean isVisibleRequested() {
+ return isVisible();
+ }
+
+ @Override
void onAppTransitionDone() {
super.onAppTransitionDone();
mWmService.mWindowsChanged = true;
@@ -4432,6 +4446,7 @@
}
void executeAppTransition() {
+ mAtmService.getTransitionController().setReady();
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 251c014..231cc97 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -63,26 +63,8 @@
}
/**
- * Update visibility to activities.
- * @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean)
- * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
- * @param starting The top most activity in the task.
- * The activity is either starting or resuming.
- * Caller should ensure starting activity is visible.
- *
- */
- void processUpdate(@Nullable ActivityRecord starting) {
- reset(starting, 0 /* configChanges */, false /* preserveWindows */,
- false /* notifyClients */);
- if (DEBUG_VISIBILITY) {
- Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible processUpdate behind " + mTop);
- }
-
- mTask.forAllActivities(this::updateActivityVisibility);
- }
-
- /**
- * Commit visibility with an option to also update the configuration of visible activities.
+ * Update and commit visibility with an option to also update the configuration of visible
+ * activities.
* @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
* @param starting The top most activity in the task.
@@ -95,12 +77,13 @@
* @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
* be sent to the clients.
*/
- void processCommit(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
+ void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
+ boolean notifyClients) {
reset(starting, configChanges, preserveWindows, notifyClients);
if (DEBUG_VISIBILITY) {
- Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible processCommit behind " + mTop);
+ Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
+ + " configChanges=0x" + Integer.toHexString(configChanges));
}
if (mTop != null) {
mTask.checkTranslucentActivityWaiting(mTop);
@@ -114,25 +97,20 @@
&& (starting == null || !starting.isDescendantOf(mTask));
mTask.forAllActivities(a -> {
- commitActivityVisibility(a, starting, resumeTopActivity);
+ setActivityVisibilityState(a, starting, resumeTopActivity);
});
}
- private boolean isAboveTop(boolean isTop) {
- if (mAboveTop && !isTop) {
- return true;
- }
- mAboveTop = false;
- return false;
- }
-
- private void updateActivityVisibility(ActivityRecord r) {
+ private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
+ final boolean resumeTopActivity) {
final boolean isTop = r == mTop;
- if (isAboveTop(isTop)) {
+ if (mAboveTop && !isTop) {
return;
}
+ mAboveTop = false;
- r.updateVisibility(mBehindFullscreenActivity);
+ r.updateVisibilityIgnoringKeyguard(mBehindFullscreenActivity);
+ final boolean reallyVisible = r.shouldBeVisibleUnchecked();
// Check whether activity should be visible without Keyguard influence
if (r.visibleIgnoringKeyguard) {
@@ -149,6 +127,55 @@
}
}
+ if (reallyVisible) {
+ if (r.finishing) {
+ return;
+ }
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Make visible? " + r
+ + " finishing=" + r.finishing + " state=" + r.getState());
+ }
+ // First: if this is not the current activity being started, make
+ // sure it matches the current configuration.
+ if (r != mStarting && mNotifyClients) {
+ r.ensureActivityConfiguration(0 /* globalChanges */, mPreserveWindows,
+ true /* ignoreVisibility */);
+ }
+
+ if (!r.attachedToProcess()) {
+ makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop,
+ resumeTopActivity && isTop, r);
+ } else if (r.mVisibleRequested) {
+ // If this activity is already visible, then there is nothing to do here.
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Skipping: already visible at " + r);
+ }
+
+ if (r.mClientVisibilityDeferred && mNotifyClients) {
+ r.makeActiveIfNeeded(r.mClientVisibilityDeferred ? null : starting);
+ r.mClientVisibilityDeferred = false;
+ }
+
+ r.handleAlreadyVisible();
+ if (mNotifyClients) {
+ r.makeActiveIfNeeded(mStarting);
+ }
+ } else {
+ r.makeVisibleIfNeeded(mStarting, mNotifyClients);
+ }
+ // Aggregate current change flags.
+ mConfigChanges |= r.configChangeFlags;
+ } else {
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+ + " finishing=" + r.finishing + " state=" + r.getState()
+ + " stackShouldBeVisible=" + mContainerShouldBeVisible
+ + " behindFullscreenActivity=" + mBehindFullscreenActivity
+ + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
+ }
+ r.makeInvisible();
+ }
+
if (!mBehindFullscreenActivity && mTask.isActivityTypeHome() && r.isRootOfTask()) {
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "Home task: at " + mTask
@@ -164,60 +191,6 @@
}
}
- private void commitActivityVisibility(ActivityRecord r, ActivityRecord starting,
- final boolean resumeTopActivity) {
- final boolean isTop = r == mTop;
- if (isAboveTop(isTop)) {
- return;
- }
-
- final boolean reallyVisible = r.shouldBeVisibleUnchecked();
-
- if (reallyVisible) {
- if (r.finishing) {
- return;
- }
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
- + " finishing=" + r.finishing + " state=" + r.getState());
- // First: if this is not the current activity being started, make
- // sure it matches the current configuration.
- if (r != mStarting && mNotifyClients) {
- r.ensureActivityConfiguration(0 /* globalChanges */, mPreserveWindows,
- true /* ignoreVisibility */);
- }
-
- if (!r.attachedToProcess()) {
- makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop,
- resumeTopActivity && isTop, r);
- } else if (r.mVisibleRequested) {
- // If this activity is already visible, then there is nothing to do here.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Skipping: already visible at " + r);
-
- if (r.mClientVisibilityDeferred && mNotifyClients) {
- r.makeActiveIfNeeded(r.mClientVisibilityDeferred ? null : starting);
- r.mClientVisibilityDeferred = false;
- }
-
- r.handleAlreadyVisible();
- if (mNotifyClients) {
- r.makeActiveIfNeeded(mStarting);
- }
- } else {
- r.makeVisibleIfNeeded(mStarting, mNotifyClients);
- }
- // Aggregate current change flags.
- mConfigChanges |= r.configChangeFlags;
- } else {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
- + " finishing=" + r.finishing + " state=" + r.getState()
- + " stackShouldBeVisible=" + mContainerShouldBeVisible
- + " behindFullscreenActivity=" + mBehindFullscreenActivity
- + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
- r.makeInvisible();
- }
- }
-
private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
boolean isTop, boolean andResume, ActivityRecord r) {
// We need to make sure the app is running if it's the top, or it is just made visible from
@@ -230,12 +203,16 @@
// This activity needs to be visible, but isn't even running...
// get it started and resume if no other stack in this stack is resumed.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
+ }
if (r != starting) {
r.startFreezingScreenLocked(configChanges);
}
if (!r.mVisibleRequested || r.mLaunchTaskBehind) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
+ }
r.setVisibility(true);
}
if (r != starting) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index bad28ba..80c7366 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -125,6 +125,14 @@
}
/**
+ *
+ * @return true if the activity is controlling keyguard state.
+ */
+ boolean topActivityOccludesKeyguard(ActivityRecord r) {
+ return getDisplayState(r.getDisplayId()).mTopOccludesActivity == r;
+ }
+
+ /**
* @return {@code true} if the keyguard is going away, {@code false} otherwise.
*/
boolean isKeyguardGoingAway() {
@@ -258,15 +266,14 @@
* @return True if we may show an activity while Keyguard is showing because we are in the
* process of dismissing it anyways, false otherwise.
*/
- boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
-
+ boolean canShowActivityWhileKeyguardShowing(ActivityRecord r) {
// Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
// already the dismissing activity, in which case we don't allow it to repeatedly dismiss
// Keyguard.
- return dismissKeyguard && canDismissKeyguard() && !mAodShowing
+ return r.containsDismissKeyguardWindow() && canDismissKeyguard() && !mAodShowing
&& (mDismissalRequested
|| (r.canShowWhenLocked()
- && getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r));
+ && getDisplayState(r.getDisplayId()).mDismissingKeyguardActivity != r));
}
/**
@@ -290,7 +297,7 @@
if (isKeyguardOrAodShowing(r.mDisplayContent.getDisplayId())) {
// If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
// right away and AOD isn't visible.
- return canShowActivityWhileKeyguardShowing(r, r.containsDismissKeyguardWindow());
+ return canShowActivityWhileKeyguardShowing(r);
} else if (isKeyguardLocked()) {
return canShowWhileOccluded(r.containsDismissKeyguardWindow(), r.canShowWhenLocked());
} else {
@@ -299,16 +306,17 @@
}
/**
- * Makes sure to update lockscreen occluded/dismiss state if needed after completing all
- * visibility updates ({@link ActivityStackSupervisor#endActivityVisibilityUpdate}).
+ * Makes sure to update lockscreen occluded/dismiss/turnScreenOn state if needed before
+ * completing set all visibility
+ * ({@link ActivityStackSupervisor#beginActivityVisibilityUpdate}).
*/
- void visibilitiesUpdated() {
+ void updateVisibility() {
boolean requestDismissKeyguard = false;
for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
- final KeyguardDisplayState state = getDisplay(display.mDisplayId);
- state.visibilitiesUpdated(this, display);
+ final KeyguardDisplayState state = getDisplayState(display.mDisplayId);
+ state.updateVisibility(this, display);
requestDismissKeyguard |= state.mRequestDismissKeyguard;
}
@@ -340,7 +348,6 @@
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
updateKeyguardSleepToken(DEFAULT_DISPLAY);
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} finally {
mService.continueWindowLayout();
@@ -370,13 +377,12 @@
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
0 /* flags */, true /* forceOverride */);
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
}
}
- private boolean isDisplayOccluded(int displayId) {
- return getDisplay(displayId).mOccluded;
+ boolean isDisplayOccluded(int displayId) {
+ return getDisplayState(displayId).mOccluded;
}
/**
@@ -433,7 +439,7 @@
}
private void updateKeyguardSleepToken(int displayId) {
- final KeyguardDisplayState state = getDisplay(displayId);
+ final KeyguardDisplayState state = getDisplayState(displayId);
if (isKeyguardUnoccludedOrAodShowing(displayId)) {
state.mSleepTokenAcquirer.acquire(displayId);
} else if (!isKeyguardUnoccludedOrAodShowing(displayId)) {
@@ -441,7 +447,7 @@
}
}
- private KeyguardDisplayState getDisplay(int displayId) {
+ private KeyguardDisplayState getDisplayState(int displayId) {
KeyguardDisplayState state = mDisplayStates.get(displayId);
if (state == null) {
state = new KeyguardDisplayState(mService, displayId, mSleepTokenAcquirer);
@@ -462,8 +468,11 @@
private static class KeyguardDisplayState {
private final int mDisplayId;
private boolean mOccluded;
+
+ private ActivityRecord mTopOccludesActivity;
private ActivityRecord mDismissingKeyguardActivity;
private ActivityRecord mTopTurnScreenOnActivity;
+
private boolean mRequestDismissKeyguard;
private final ActivityTaskManagerService mService;
private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
@@ -476,58 +485,77 @@
}
void onRemoved() {
+ mTopOccludesActivity = null;
mDismissingKeyguardActivity = null;
mTopTurnScreenOnActivity = null;
mSleepTokenAcquirer.release(mDisplayId);
}
- void visibilitiesUpdated(KeyguardController controller, DisplayContent display) {
+ /**
+ * Updates {@link #mOccluded}, {@link #mTopTurnScreenOnActivity} and
+ * {@link #mDismissingKeyguardActivity} if the top task could be visible.
+ */
+ void updateVisibility(KeyguardController controller, DisplayContent display) {
final boolean lastOccluded = mOccluded;
- final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
+
+ final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity;
final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
+
mRequestDismissKeyguard = false;
mOccluded = false;
+
+ mTopOccludesActivity = null;
mDismissingKeyguardActivity = null;
mTopTurnScreenOnActivity = null;
- // only top + focusable + visible task can control occluding.
- final Task stack = getStackForControllingOccluding(display);
- if (stack != null) {
- final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
- final ActivityRecord topTurnScreenOn = stack.getTopTurnScreenOnActivity();
- mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
- && stack.topRunningActivity() == topDismissing
- && controller.canShowWhileOccluded(
- true /* dismissKeyguard */,
- false /* showWhenLocked */));
- if (topDismissing != null) {
- mDismissingKeyguardActivity = topDismissing;
- }
- if (topTurnScreenOn != null) {
- mTopTurnScreenOnActivity = topTurnScreenOn;
- }
- // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
- if (mDisplayId != DEFAULT_DISPLAY && stack.mDisplayContent != null) {
- mOccluded |= stack.mDisplayContent.canShowWithInsecureKeyguard()
- && controller.canDismissKeyguard();
+ boolean occludedByActivity = false;
+ final Task task = getRootTaskForControllingOccluding(display);
+ if (task != null) {
+ final ActivityRecord r = task.getTopNonFinishingActivity();
+ if (r != null) {
+ final boolean showWhenLocked = r.canShowWhenLocked();
+ if (r.containsDismissKeyguardWindow()) {
+ mDismissingKeyguardActivity = r;
+ }
+ if (r.getTurnScreenOnFlag()
+ && r.currentLaunchCanTurnScreenOn()) {
+ mTopTurnScreenOnActivity = r;
+ }
+
+ if (showWhenLocked) {
+ mTopOccludesActivity = r;
+ }
+
+ // Only the top activity may control occluded, as we can't occlude the Keyguard
+ // if the top app doesn't want to occlude it.
+ occludedByActivity = showWhenLocked || (mDismissingKeyguardActivity != null
+ && task.topRunningActivity() == mDismissingKeyguardActivity
+ && controller.canShowWhileOccluded(
+ true /* dismissKeyguard */, false /* showWhenLocked */));
+ // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
+ if (mDisplayId != DEFAULT_DISPLAY && task.mDisplayContent != null) {
+ occludedByActivity |=
+ task.mDisplayContent.canShowWithInsecureKeyguard()
+ && controller.canDismissKeyguard();
+ }
}
}
// TODO(b/123372519): isShowingDream can only works on default display.
- if (mDisplayId == DEFAULT_DISPLAY) {
- mOccluded |= mService.mRootWindowContainer.getDefaultDisplay()
- .getDisplayPolicy().isShowingDreamLw();
- }
-
- mRequestDismissKeyguard = lastDismissActivity != mDismissingKeyguardActivity
+ mOccluded = occludedByActivity || (mDisplayId == DEFAULT_DISPLAY
+ && mService.mRootWindowContainer.getDefaultDisplay()
+ .getDisplayPolicy().isShowingDreamLw());
+ mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
&& !mOccluded
&& mDismissingKeyguardActivity != null
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- if (mTopTurnScreenOnActivity != null
- && mTopTurnScreenOnActivity != lastTurnScreenOnActivity
- && !mService.mWindowManager.mPowerManager.isInteractive()) {
+ if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
+ && mTopTurnScreenOnActivity != null
+ && !mService.mWindowManager.mPowerManager.isInteractive()
+ && (mRequestDismissKeyguard || occludedByActivity)) {
controller.mStackSupervisor.wakeUp("handleTurnScreenOn");
+ mTopOccludesActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
@@ -542,13 +570,13 @@
* occlusion state.
*/
@Nullable
- private Task getStackForControllingOccluding(DisplayContent display) {
+ private Task getRootTaskForControllingOccluding(DisplayContent display) {
return display.getItemFromTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
- if (stack != null && stack.isFocusableAndVisible()
- && !stack.inPinnedWindowingMode()) {
- return stack;
+ final Task task = taskDisplayArea.getStackAt(sNdx);
+ if (task != null && task.isFocusableAndVisible()
+ && !task.inPinnedWindowingMode()) {
+ return task;
}
}
return null;
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 56e1187..a0074a2 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -144,11 +144,11 @@
mTmpParams.mPreferredTaskDisplayArea, true /* onTop */);
}
- if (mTmpParams.hasWindowingMode()
- && mTmpParams.mWindowingMode != task.getRootTask().getWindowingMode()) {
+ if (mTmpParams.hasWindowingMode() && task.isRootTask()
+ && mTmpParams.mWindowingMode != task.getWindowingMode()) {
final int activityType = activity != null
? activity.getActivityType() : task.getActivityType();
- task.getRootTask().setWindowingMode(task.getDisplayArea().validateWindowingMode(
+ task.setWindowingMode(task.getDisplayArea().validateWindowingMode(
mTmpParams.mWindowingMode, activity, task, activityType));
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 255b3f1..d292580 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -35,10 +35,10 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.SYSTEM_UID;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -72,6 +72,7 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
@@ -157,7 +158,8 @@
*/
private int mRecentsUid = -1;
private ComponentName mRecentsComponent = null;
- private @Nullable String mFeatureId;
+ @Nullable
+ private String mFeatureId;
/**
* Mapping of user id -> whether recent tasks have been loaded for that user.
@@ -397,7 +399,7 @@
/**
* @return whether the given component is the recents component and shares the same uid as the
- * recents component.
+ * recents component.
*/
boolean isRecentsComponent(ComponentName cn, int uid) {
return cn.equals(mRecentsComponent) && UserHandle.isSameApp(uid, mRecentsUid);
@@ -423,7 +425,8 @@
/**
* @return the featureId for the recents component.
*/
- @Nullable String getRecentsComponentFeatureId() {
+ @Nullable
+ String getRecentsComponentFeatureId() {
return mFeatureId;
}
@@ -617,7 +620,7 @@
/** Remove recent tasks for a user. */
private void removeTasksForUserLocked(int userId) {
- if(userId <= 0) {
+ if (userId <= 0) {
Slog.i(TAG, "Can't remove recent task on user " + userId);
return;
}
@@ -625,8 +628,8 @@
for (int i = mTasks.size() - 1; i >= 0; --i) {
Task task = mTasks.get(i);
if (task.mUserId == userId) {
- if(DEBUG_TASKS) Slog.i(TAG_TASKS,
- "remove RecentTask " + task + " when finishing user" + userId);
+ ProtoLog.i(WM_DEBUG_TASKS, "remove RecentTask %s when finishing user "
+ + "%d", task, userId);
remove(task);
}
}
@@ -640,11 +643,11 @@
&& packageNames.contains(task.realActivity.getPackageName())
&& task.mUserId == userId
&& task.realActivitySuspended != suspended) {
- task.realActivitySuspended = suspended;
- if (suspended) {
- mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "suspended-package");
- }
- notifyTaskPersisterLocked(task, false);
+ task.realActivitySuspended = suspended;
+ if (suspended) {
+ mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "suspended-package");
+ }
+ notifyTaskPersisterLocked(task, false);
}
}
}
@@ -780,25 +783,31 @@
continue;
} else {
// Otherwise just not available for now.
- if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
- "Making recent unavailable: " + task);
+ if (DEBUG_RECENTS && task.isAvailable) {
+ Slog.d(TAG_RECENTS,
+ "Making recent unavailable: " + task);
+ }
task.isAvailable = false;
}
} else {
if (!ai.enabled || !ai.applicationInfo.enabled
|| (ai.applicationInfo.flags
- & ApplicationInfo.FLAG_INSTALLED) == 0) {
- if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
- "Making recent unavailable: " + task
- + " (enabled=" + ai.enabled + "/"
- + ai.applicationInfo.enabled
- + " flags="
- + Integer.toHexString(ai.applicationInfo.flags)
- + ")");
+ & ApplicationInfo.FLAG_INSTALLED) == 0) {
+ if (DEBUG_RECENTS && task.isAvailable) {
+ Slog.d(TAG_RECENTS,
+ "Making recent unavailable: " + task
+ + " (enabled=" + ai.enabled + "/"
+ + ai.applicationInfo.enabled
+ + " flags="
+ + Integer.toHexString(ai.applicationInfo.flags)
+ + ")");
+ }
task.isAvailable = false;
} else {
- if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
- "Making recent available: " + task);
+ if (DEBUG_RECENTS && !task.isAvailable) {
+ Slog.d(TAG_RECENTS,
+ "Making recent available: " + task);
+ }
task.isAvailable = true;
}
}
@@ -974,16 +983,20 @@
final int size = mTasks.size();
for (int i = 0; i < size; i++) {
final Task task = mTasks.get(i);
- if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
- + " persistable=" + task.isPersistable);
+ if (TaskPersister.DEBUG) {
+ Slog.d(TAG, "LazyTaskWriter: task=" + task
+ + " persistable=" + task.isPersistable);
+ }
final Task rootTask = task.getRootTask();
if ((task.isPersistable || task.inRecents)
&& (rootTask == null || !rootTask.isHomeOrRecentsStack())) {
if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
persistentTaskIds.add(task.mTaskId);
} else {
- if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task="
- + task);
+ if (TaskPersister.DEBUG) {
+ Slog.d(TAG, "omitting from persistentTaskIds task="
+ + task);
+ }
}
}
}
@@ -1051,8 +1064,10 @@
// TODO: VI what about if it's just an activity?
// Probably nothing to do here
if (task.voiceSession != null) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "addRecent: not adding voice interaction " + task);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS,
+ "addRecent: not adding voice interaction " + task);
+ }
return;
}
// Another quick case: check if the top-most recent task is the same.
@@ -1064,8 +1079,10 @@
// tasks that are at the top.
if (isAffiliated && recentsCount > 0 && task.inRecents
&& task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
- + " at top when adding " + task);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
+ + " at top when adding " + task);
+ }
return;
}
@@ -1122,14 +1139,17 @@
if (other == task.mNextAffiliate) {
// We found the index of our next affiliation, which is who is
// before us in the list, so add after that point.
- taskIndex = otherIndex+1;
+ taskIndex = otherIndex + 1;
} else {
// We found the index of our previous affiliation, which is who is
// after us in the list, so add at their position.
taskIndex = otherIndex;
}
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "addRecent: new affiliated task added at " + taskIndex + ": " + task);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS,
+ "addRecent: new affiliated task added at " + taskIndex + ": "
+ + task);
+ }
mTasks.add(taskIndex, task);
notifyTaskAdded(task);
@@ -1143,13 +1163,17 @@
// everything and then go through our general path of adding a new task.
needAffiliationFix = true;
} else {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "addRecent: couldn't find other affiliation " + other);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS,
+ "addRecent: couldn't find other affiliation " + other);
+ }
needAffiliationFix = true;
}
} else {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "addRecent: adding affiliated task without next/prev:" + task);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS,
+ "addRecent: adding affiliated task without next/prev:" + task);
+ }
needAffiliationFix = true;
}
}
@@ -1204,8 +1228,10 @@
final Task task = mTasks.remove(recentsCount - 1);
notifyTaskRemoved(task, true /* wasTrimmed */, false /* killProcess */);
recentsCount--;
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + task
- + " max=" + mGlobalMaxNumTasks);
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "Trimming over max-recents task=" + task
+ + " max=" + mGlobalMaxNumTasks);
+ }
}
// Remove any tasks that belong to currently quiet profiles
@@ -1216,13 +1242,15 @@
if (userInfo != null && userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) {
mTmpQuietProfileUserIds.put(userId, true);
}
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo
- + " quiet=" + mTmpQuietProfileUserIds.get(userId));
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "User: " + userInfo
+ + " quiet=" + mTmpQuietProfileUserIds.get(userId));
+ }
}
// Remove any inactive tasks, calculate the latest set of visible tasks.
int numVisibleTasks = 0;
- for (int i = 0; i < mTasks.size();) {
+ for (int i = 0; i < mTasks.size(); ) {
final Task task = mTasks.get(i);
if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
@@ -1246,8 +1274,10 @@
} else {
// Fall through to trim visible tasks that are no longer in range and
// trimmable
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
- "Trimming out-of-range visible task=" + task);
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG,
+ "Trimming out-of-range visible task=" + task);
+ }
}
}
} else {
@@ -1266,8 +1296,10 @@
* @return whether the given task should be considered active.
*/
private boolean isActiveRecentTask(Task task, SparseBooleanArray quietProfileUserIds) {
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
- + " globalMax=" + mGlobalMaxNumTasks);
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "isActiveRecentTask: task=" + task
+ + " globalMax=" + mGlobalMaxNumTasks);
+ }
if (quietProfileUserIds.get(task.mUserId)) {
// Quiet profile user's tasks are never active
@@ -1280,8 +1312,10 @@
final Task affiliatedTask = getTask(task.mAffiliatedTaskId);
if (affiliatedTask != null) {
if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
- "\taffiliatedWithTask=" + affiliatedTask + " is not active");
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG,
+ "\taffiliatedWithTask=" + affiliatedTask + " is not active");
+ }
return false;
}
}
@@ -1296,13 +1330,15 @@
*/
@VisibleForTesting
boolean isVisibleRecentTask(Task task) {
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
- + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
- + " sessionDuration=" + mActiveTasksSessionDurationMs
- + " inactiveDuration=" + task.getInactiveDuration()
- + " activityType=" + task.getActivityType()
- + " windowingMode=" + task.getWindowingMode()
- + " intentFlags=" + task.getBaseIntent().getFlags());
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "isVisibleRecentTask: task=" + task
+ + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
+ + " sessionDuration=" + mActiveTasksSessionDurationMs
+ + " inactiveDuration=" + task.getInactiveDuration()
+ + " activityType=" + task.getActivityType()
+ + " windowingMode=" + task.getWindowingMode()
+ + " intentFlags=" + task.getBaseIntent().getFlags());
+ }
switch (task.getActivityType()) {
case ACTIVITY_TYPE_HOME:
@@ -1468,8 +1504,10 @@
mHiddenTasks.add(removedTask);
}
notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
- + " for addition of task=" + task);
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "Trimming task=" + removedTask
+ + " for addition of task=" + task);
+ }
}
notifyTaskPersisterLocked(removedTask, false /* flush */);
}
@@ -1622,16 +1660,20 @@
top = top.mNextAffiliate;
topIndex--;
}
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
- + topIndex + " from intial " + taskIndex);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: adding affiliates starting at "
+ + topIndex + " from initial " + taskIndex);
+ }
// Find the end of the chain, doing a validity check along the way.
boolean isValid = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
int endIndex = topIndex;
Task prev = top;
while (endIndex < recentsCount) {
Task cur = mTasks.get(endIndex);
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
- + endIndex + " " + cur);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
+ + endIndex + " " + cur);
+ }
if (cur == top) {
// Verify start of the chain.
if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
@@ -1701,14 +1743,18 @@
if (isValid) {
// All looks good, we can just move all of the affiliated tasks
// to the top.
- for (int i=topIndex; i<=endIndex; i++) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
- + " from " + i + " to " + (i-topIndex));
+ for (int i = topIndex; i <= endIndex; i++) {
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
+ + " from " + i + " to " + (i - topIndex));
+ }
Task cur = mTasks.remove(i);
mTasks.add(i - topIndex, cur);
}
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex
- + " to " + endIndex);
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex
+ + " to " + endIndex);
+ }
return true;
}
@@ -1768,7 +1814,9 @@
printedHeader = true;
printedAnything = true;
}
- pw.print(" * Recent #"); pw.print(i); pw.print(": ");
+ pw.print(" * Recent #");
+ pw.print(i);
+ pw.print(": ");
pw.println(task);
if (dumpAll) {
task.dump(pw, " ");
@@ -1787,7 +1835,7 @@
boolean match = taskInfo.baseIntent != null
&& taskInfo.baseIntent.getComponent() != null
&& dumpPackage.equals(
- taskInfo.baseIntent.getComponent().getPackageName());
+ taskInfo.baseIntent.getComponent().getPackageName());
if (!match) {
match |= taskInfo.baseActivity != null
&& dumpPackage.equals(taskInfo.baseActivity.getPackageName());
@@ -1818,7 +1866,9 @@
printedAnything = true;
}
- pw.print(" * RecentTaskInfo #"); pw.print(i); pw.print(": ");
+ pw.print(" * RecentTaskInfo #");
+ pw.print(i);
+ pw.print(": ");
taskInfo.dump(pw, " ");
}
}
@@ -1842,8 +1892,8 @@
/**
* @return Whether the activity types and windowing modes of the two tasks are considered
- * compatible. This is necessary because we currently don't persist the activity type
- * or the windowing mode with the task, so they can be undefined when restored.
+ * compatible. This is necessary because we currently don't persist the activity type
+ * or the windowing mode with the task, so they can be undefined when restored.
*/
private boolean hasCompatibleActivityTypeAndWindowingMode(Task t1, Task t2) {
final int activityType = t1.getActivityType();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 35338bb..1cf50ab 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -161,7 +161,7 @@
}
}
- void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) {
+ void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner, long eventTime) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity");
@@ -249,8 +249,13 @@
// we fetch the visible tasks to be controlled by the animation
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ ActivityOptions options = null;
+ if (eventTime > 0) {
+ options = ActivityOptions.makeBasic();
+ options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
+ }
mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, targetActivity, null /* options */);
+ START_TASK_TO_FRONT, targetActivity, options);
// Register for stack order changes
mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 42a20ff..38d20a8 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -932,7 +932,7 @@
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
- mIsRecentTaskInvisible, null, null);
+ mIsRecentTaskInvisible, null, null, mTask.getPictureInPictureParams());
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index c3953b4..9181a0f 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -17,14 +17,12 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.TAG_TASKS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Debug;
-import android.util.Slog;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -201,8 +199,8 @@
noOptions = takeOption(p, noOptions);
- if (DEBUG_TASKS) Slog.w(TAG_TASKS,
- "resetTaskIntendedTask: calling finishActivity on " + p);
+ ProtoLog.w(WM_DEBUG_TASKS, "resetTaskIntendedTask: calling finishActivity "
+ + "on %s", p);
p.finishIfPossible(reason, false /* oomAdj */);
}
}
@@ -213,15 +211,15 @@
while (!mResultActivities.isEmpty()) {
final ActivityRecord p = mResultActivities.remove(0);
- if (ignoreFinishing&& p.finishing) continue;
+ if (ignoreFinishing && p.finishing) continue;
if (takeOptions) {
noOptions = takeOption(p, noOptions);
}
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s "
- + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4));
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Pushing next activity " + p + " out to target's task " + target);
+ + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4));
+ ProtoLog.v(WM_DEBUG_TASKS, "Pushing next activity %s out to target's task %s", p,
+ target);
p.reparent(targetTask, position, "resetTargetTaskIfNeeded");
}
}
@@ -253,8 +251,8 @@
// If the activity currently at the bottom has the same task affinity as
// the one we are moving, then merge it into the same task.
targetTask = task;
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
- + r + " out to bottom task " + targetTask);
+ ProtoLog.v(WM_DEBUG_TASKS, "Start pushing activity %s out to bottom task %s", r,
+ targetTask);
}
if (targetTask == null) {
if (alwaysCreateTask) {
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index faed7fa..d9a8773 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -27,7 +27,8 @@
/**
* Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root
- * of the whole logical display, or the root of a {@link DisplayArea} group.
+ * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the
+ * logical display.
*/
class RootDisplayArea extends DisplayArea<DisplayArea> {
@@ -50,6 +51,16 @@
super(wms, Type.ANY, name, featureId);
}
+ @Override
+ RootDisplayArea getRootDisplayArea() {
+ return this;
+ }
+
+ /** Whether the orientation (based on dimensions) of this root is different from the Display. */
+ boolean isOrientationDifferentFromDisplay() {
+ return false;
+ }
+
/** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
DisplayArea.Tokens findAreaForToken(WindowToken token) {
int windowLayerFromType = token.getWindowLayerFromType();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8b52b58..cabf1bf 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -44,6 +44,8 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
@@ -55,11 +57,8 @@
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
@@ -179,7 +178,6 @@
private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
static final String TAG_TASKS = TAG + POSTFIX_TASKS;
- private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -235,7 +233,9 @@
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
})
- public @interface AnyTaskForIdMatchTaskMode {}
+ public @interface AnyTaskForIdMatchTaskMode {
+ }
+
// Match only tasks in the current stacks
static final int MATCH_TASK_IN_STACKS_ONLY = 0;
// Match either tasks in the current stacks, or in the recent tasks if not found in the stacks
@@ -305,6 +305,7 @@
};
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
+
static class FindTaskResult implements Function<Task, Boolean> {
ActivityRecord mRecord;
boolean mIdealMatch;
@@ -335,7 +336,8 @@
// If documentData is non-null then it must match the existing task data.
documentData = isDocument ? intent.getData() : null;
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + parent);
+ ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", target,
+ parent);
parent.forAllLeafTasks(this);
}
@@ -353,12 +355,12 @@
public Boolean apply(Task task) {
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: voice session", task);
return false;
}
if (task.mUserId != userId) {
// Looking for a different task.
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: different user", task);
return false;
}
@@ -366,11 +368,11 @@
final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
if (r == null || r.finishing || r.mUserId != userId
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
return false;
}
if (!r.hasCompatibleActivityType(mTarget)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch activity type", task);
return false;
}
@@ -389,40 +391,40 @@
taskDocumentData = null;
}
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
- + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
- + "/aff=" + r.getTask().rootAffinity + " to new cls="
- + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
+ ProtoLog.d(WM_DEBUG_TASKS, "Comparing existing cls=%s /aff=%s to new cls=%s /aff=%s",
+ r.getTask().rootAffinity, intent.getComponent().flattenToShortString(),
+ info.taskAffinity, (task.realActivity != null
+ ? task.realActivity.flattenToShortString() : ""));
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
&& Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+ ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
//dump();
- if (DEBUG_TASKS) Slog.d(TAG_TASKS,
- "For Intent " + intent + " bringing to top: " + r.intent);
+ ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
mRecord = r;
mIdealMatch = true;
return true;
} else if (affinityIntent != null && affinityIntent.getComponent() != null
&& affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
- if (DEBUG_TASKS) Slog.d(TAG_TASKS,
- "For Intent " + intent + " bringing to top: " + r.intent);
+ ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
+ ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
mRecord = r;
mIdealMatch = true;
return true;
} else if (!isDocument && !taskIsDocument
&& mRecord == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(mTarget.taskAffinity)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+ ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
mRecord = r;
mIdealMatch = false;
}
- } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
+ } else {
+ ProtoLog.d(WM_DEBUG_TASKS, "Not a match: %s", task);
+ }
return false;
}
@@ -578,6 +580,7 @@
* Returns {@code true} if the callingUid has any non-toast window currently visible to the
* user. Also ignores {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
* since those windows don't belong to apps.
+ *
* @see WindowState#isNonToastOrStarting()
*/
boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
@@ -791,7 +794,7 @@
"Looks like we have reclaimed some memory, clearing surface for retry.");
if (surfaceController != null) {
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
- "SURFACE RECOVER DESTROY: %s", winAnimator.mWin);
+ "SURFACE RECOVER DESTROY: %s", winAnimator.mWin);
winAnimator.destroySurface();
if (winAnimator.mWin.mActivityRecord != null) {
winAnimator.mWin.mActivityRecord.removeStartingWindow();
@@ -822,8 +825,10 @@
// "Something has changed! Let's make it correct now."
// TODO: Super long method that should be broken down...
void performSurfacePlacementNoTrace() {
- if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
- + Debug.getCallers(3));
+ if (DEBUG_WINDOW_TRACE) {
+ Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+ + Debug.getCallers(3));
+ }
int i;
@@ -851,8 +856,10 @@
final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG,
+ ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+ }
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
@@ -862,8 +869,10 @@
} finally {
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG,
+ "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+ }
}
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
@@ -896,8 +905,10 @@
if (isLayoutNeeded()) {
defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("mLayoutNeeded",
- defaultDisplay.pendingLayoutChanges);
+ if (DEBUG_LAYOUT_REPEATS) {
+ surfacePlacer.debugLayoutRepeats("mLayoutNeeded",
+ defaultDisplay.pendingLayoutChanges);
+ }
}
handleResizingWindows();
@@ -1105,11 +1116,11 @@
}
/**
- * @param w WindowState this method is applied to.
+ * @param w WindowState this method is applied to.
* @param obscured True if there is a window on top of this obscuring the display.
- * @param syswin System window?
+ * @param syswin System window?
* @return True when the display contains content to show the user. When false, the display
- * manager may choose to mirror or blank the display.
+ * manager may choose to mirror or blank the display.
*/
boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {
final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -1243,7 +1254,8 @@
}
void dumpTopFocusedDisplayId(PrintWriter pw) {
- pw.print(" mTopFocusedDisplayId="); pw.println(mTopFocusedDisplayId);
+ pw.print(" mTopFocusedDisplayId=");
+ pw.println(mTopFocusedDisplayId);
}
void dumpLayoutNeededDisplayIds(PrintWriter pw) {
@@ -1359,7 +1371,8 @@
}
}
- @Nullable Context getDisplayUiContext(int displayId) {
+ @Nullable
+ Context getDisplayUiContext(int displayId) {
return getDisplayContent(displayId) != null
? getDisplayContent(displayId).getDisplayUiContext() : null;
}
@@ -1437,7 +1450,8 @@
* corresponding record in display manager.
*/
// TODO: Look into consolidating with getDisplayContent()
- @Nullable DisplayContent getDisplayContentOrCreate(int displayId) {
+ @Nullable
+ DisplayContent getDisplayContentOrCreate(int displayId) {
DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
return displayContent;
@@ -1494,8 +1508,8 @@
final DisplayContent display = getDisplayContent(displayId);
return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
- result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
- allowInstrumenting, fromHomeKey),
+ result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
+ allowInstrumenting, fromHomeKey),
false /* initValue */);
}
@@ -1504,11 +1518,11 @@
* displayId - default display area always uses primary home component.
* For secondary display areas, the home activity must have category SECONDARY_HOME and then
* resolves according to the priorities listed below.
- * - If default home is not set, always use the secondary home defined in the config.
- * - Use currently selected primary home activity.
- * - Use the activity in the same package as currently selected primary home activity.
- * If there are multiple activities matched, use first one.
- * - Use the secondary home defined in the config.
+ * - If default home is not set, always use the secondary home defined in the config.
+ * - Use currently selected primary home activity.
+ * - Use the activity in the same package as currently selected primary home activity.
+ * If there are multiple activities matched, use first one.
+ * - Use the secondary home defined in the config.
*/
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
boolean allowInstrumenting, boolean fromHomeKey) {
@@ -1556,6 +1570,7 @@
/**
* This resolves the home activity info.
+ *
* @return the home activity info if any.
*/
@VisibleForTesting
@@ -1629,7 +1644,8 @@
}
if (aInfo != null) {
- if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, false /* allowInstrumenting */)) {
+ if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea,
+ false /* allowInstrumenting */)) {
aInfo = null;
}
}
@@ -1687,6 +1703,7 @@
/**
* Check if the display area is valid for secondary home activity.
+ *
* @param taskDisplayArea The target display area.
* @return {@code true} if allow to launch, {@code false} otherwise.
*/
@@ -1727,8 +1744,10 @@
/**
* Check if home activity start should be allowed on a display.
- * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched.
- * @param taskDisplayArea The target display area.
+ *
+ * @param homeInfo {@code ActivityInfo} of the home activity that is going to be
+ * launched.
+ * @param taskDisplayArea The target display area.
* @param allowInstrumenting Whether launching home should be allowed if being instrumented.
* @return {@code true} if allow to launch, {@code false} otherwise.
*/
@@ -1773,13 +1792,14 @@
/**
* Ensure all activities visibility, update orientation and configuration.
*
- * @param starting The currently starting activity or {@code null} if there is none.
- * @param displayId The id of the display where operation is executed.
+ * @param starting The currently starting activity or {@code null} if there is
+ * none.
+ * @param displayId The id of the display where operation is executed.
* @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to
* {@code true} if config changed.
- * @param deferResume Whether to defer resume while updating config.
+ * @param deferResume Whether to defer resume while updating config.
* @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched
- * because of configuration update.
+ * because of configuration update.
*/
boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
boolean markFrozenIfConfigChanged, boolean deferResume) {
@@ -2003,22 +2023,10 @@
notifyClients);
}
} finally {
- mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges, preserveWindows,
- notifyClients);
+ mStackSupervisor.endActivityVisibilityUpdate();
}
}
- void commitActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
- forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int stackNdx = taskDisplayArea.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final Task task = taskDisplayArea.getStackAt(stackNdx);
- task.commitActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
- }
- });
- }
-
boolean switchUser(int userId, UserState uss) {
final Task topFocusedStack = getTopDisplayFocusedStack();
final int focusStackId = topFocusedStack != null
@@ -2078,9 +2086,10 @@
/**
* Move stack with all its existing content to specified task display area.
- * @param stackId Id of stack to move.
+ *
+ * @param stackId Id of stack to move.
* @param taskDisplayArea The task display area to move stack to.
- * @param onTop Indicates whether container should be place on top or on bottom.
+ * @param onTop Indicates whether container should be place on top or on bottom.
*/
void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) {
final Task stack = getStack(stackId);
@@ -2110,9 +2119,10 @@
/**
* Move stack with all its existing content to specified display.
- * @param stackId Id of stack to move.
+ *
+ * @param stackId Id of stack to move.
* @param displayId Id of display to move stack to.
- * @param onTop Indicates whether container should be place on top or on bottom.
+ * @param onTop Indicates whether container should be place on top or on bottom.
*/
void moveStackToDisplay(int stackId, int displayId, boolean onTop) {
final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
@@ -2204,7 +2214,7 @@
final ActivityRecord oldTopActivity = task.getTopMostActivity();
if (oldTopActivity != null && oldTopActivity.isState(STOPPED)
&& task.getDisplayContent().mAppTransition.getAppTransition()
- == TRANSIT_TASK_TO_BACK) {
+ == TRANSIT_TASK_TO_BACK) {
task.getDisplayContent().mClosingApps.add(oldTopActivity);
oldTopActivity.mRequestForceTransition = true;
}
@@ -2239,6 +2249,7 @@
/**
* Notifies when an activity enters or leaves PIP mode.
+ *
* @param r indicates the activity currently in PIP, can be null to indicate no activity is
* currently in PIP mode.
*/
@@ -2261,7 +2272,7 @@
@Nullable
ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
+ ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s", r);
mTmpFindTaskResult.clear();
// Looking up task on preferred display area first
@@ -2289,13 +2300,16 @@
return task;
}
- if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found");
+ if (WM_DEBUG_TASKS.isEnabled() && mTmpFindTaskResult.mRecord == null) {
+ ProtoLog.d(WM_DEBUG_TASKS, "No task found");
+ }
return mTmpFindTaskResult.mRecord;
}
/**
* Finish the topmost activities in all stacks that belong to the crashed app.
- * @param app The app that crashed.
+ *
+ * @param app The app that crashed.
* @param reason Reason to perform this action.
* @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
@@ -2763,9 +2777,11 @@
private void destroyActivity(ActivityRecord r) {
if (r.finishing || !r.isDestroyable()) return;
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
- + " resumed=" + r.getStack().mResumedActivity + " pausing="
- + r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
+ if (DEBUG_SWITCH) {
+ Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
+ + " resumed=" + r.getStack().mResumedActivity + " pausing="
+ + r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
+ }
r.destroyImmediately(mDestroyAllActivitiesReason);
}
@@ -2826,7 +2842,7 @@
private static boolean matchesActivity(ActivityRecord r, int userId,
boolean compareIntentFilters, Intent intent, ComponentName cls) {
- if (!r.canBeTopRunning() || r.mUserId != userId) return false;
+ if (!r.canBeTopRunning() || r.mUserId != userId) return false;
if (compareIntentFilters) {
if (r.intent.filterEquals(intent)) {
@@ -2861,10 +2877,10 @@
/**
* Returns the right stack to use for launching factoring in all the input parameters.
*
- * @param r The activity we are trying to launch. Can be null.
- * @param options The activity options used to the launch. Can be null.
- * @param candidateTask The possible task the activity might be launched in. Can be null.
- * @param launchParams The resolved launch params to use.
+ * @param r The activity we are trying to launch. Can be null.
+ * @param options The activity options used to the launch. Can be null.
+ * @param candidateTask The possible task the activity might be launched in. Can be null.
+ * @param launchParams The resolved launch params to use.
* @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
* @return The stack to use for the launch or INVALID_STACK_ID.
@@ -2998,9 +3014,10 @@
/**
* Get a topmost stack on the display area, that is a valid launch stack for specified activity.
* If there is no such stack, new dynamic stack can be created.
+ *
* @param taskDisplayArea Target display area.
- * @param r Activity that should be launched there.
- * @param candidateTask The possible task the activity might be put in.
+ * @param r Activity that should be launched there.
+ * @param candidateTask The possible task the activity might be put in.
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
@VisibleForTesting
@@ -3066,10 +3083,14 @@
// TODO: Can probably be consolidated into getLaunchStack()...
private boolean isValidLaunchStack(Task stack, ActivityRecord r, int windowingMode) {
switch (stack.getActivityType()) {
- case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome();
- case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
- case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
- case ACTIVITY_TYPE_DREAM: return r.isActivityTypeDream();
+ case ACTIVITY_TYPE_HOME:
+ return r.isActivityTypeHome();
+ case ACTIVITY_TYPE_RECENTS:
+ return r.isActivityTypeRecents();
+ case ACTIVITY_TYPE_ASSISTANT:
+ return r.isActivityTypeAssistant();
+ case ACTIVITY_TYPE_DREAM:
+ return r.isActivityTypeDream();
}
if (stack.mCreatedByOrganizer) {
// Don't launch directly into task created by organizer...but why can't we?
@@ -3109,9 +3130,9 @@
* from the target stack. If no valid candidates will be found, it will then go through all
* displays and stacks in last-focused order.
*
- * @param currentFocus The stack that previously had focus.
+ * @param currentFocus The stack that previously had focus.
* @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next
- * candidate.
+ * candidate.
* @return Next focusable {@link Task}, {@code null} if not found.
*/
Task getNextFocusableStack(@NonNull Task currentFocus,
@@ -3174,6 +3195,7 @@
FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
new FinishDisabledPackageActivitiesHelper();
+
class FinishDisabledPackageActivitiesHelper {
private String mPackageName;
private Set<String> mFilterByClasses;
@@ -3330,10 +3352,8 @@
}
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity == null || !resumedActivity.idle) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
- + stack.getRootTaskId() + " " + resumedActivity + " not idle");
- }
+ ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: stack=%d %s "
+ + "not idle", stack.getRootTaskId(), resumedActivity);
return false;
}
}
@@ -3372,9 +3392,9 @@
final Task stack = taskDisplayArea.getStackAt(sNdx);
final ActivityRecord r = stack.mPausingActivity;
if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
- + " state=" + r.getState());
+ ProtoLog.d(WM_DEBUG_STATES, "allPausedActivitiesComplete: "
+ + "r=%s state=%s", r, r.getState());
+ if (WM_DEBUG_STATES.isEnabled()) {
pausing[0] = false;
} else {
return true;
@@ -3453,10 +3473,11 @@
/**
* Returns a {@link Task} for the input id if available. {@code null} otherwise.
- * @param id Id of the task we would like returned.
+ *
+ * @param id Id of the task we would like returned.
* @param matchMode The mode to match the given task id in.
- * @param aOptions The activity options to use for restoration. Can be null.
- * @param onTop If the stack for the task should be the topmost on the display.
+ * @param aOptions The activity options to use for restoration. Can be null.
+ * @param onTop If the stack for the task should be the topmost on the display.
*/
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
@Nullable ActivityOptions aOptions, boolean onTop) {
@@ -3511,8 +3532,10 @@
// Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
if (!mStackSupervisor.restoreRecentTaskLocked(task, aOptions, onTop)) {
- if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
- "Couldn't restore task id=" + id + " found in recents");
+ if (DEBUG_RECENTS) {
+ Slog.w(TAG_RECENTS,
+ "Couldn't restore task id=" + id + " found in recents");
+ }
return null;
}
if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
@@ -3623,14 +3646,19 @@
/**
* Dump all connected displays' configurations.
+ *
* @param prefix Prefix to apply to each line of the dump.
*/
void dumpDisplayConfigs(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.println("Display override configurations:");
+ pw.print(prefix);
+ pw.println("Display override configurations:");
final int displayCount = getChildCount();
for (int i = 0; i < displayCount; i++) {
final DisplayContent displayContent = getChildAt(i);
- pw.print(prefix); pw.print(" "); pw.print(displayContent.mDisplayId); pw.print(": ");
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(displayContent.mDisplayId);
+ pw.print(": ");
pw.println(displayContent.getRequestedOverrideConfiguration());
}
}
@@ -3644,7 +3672,8 @@
if (printed[0]) {
pw.println();
}
- pw.print("Display #"); pw.print(displayContent.mDisplayId);
+ pw.print("Display #");
+ pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9be4ace..f984576 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -80,6 +80,8 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -87,13 +89,9 @@
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
@@ -161,6 +159,7 @@
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.IActivityController;
+import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.app.ResultInfo;
import android.app.TaskInfo;
@@ -597,10 +596,6 @@
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
- private boolean mTopActivityOccludesKeyguard;
- private ActivityRecord mTopDismissingKeyguardActivity;
- private ActivityRecord mTopTurnScreenOnActivity;
-
private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
private final Handler mHandler;
@@ -1283,7 +1278,7 @@
_intent.setSourceBounds(null);
}
}
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
+ ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to %s", this, _intent);
intent = _intent;
realActivity = _intent != null ? _intent.getComponent() : null;
origActivity = null;
@@ -1294,8 +1289,7 @@
Intent targetIntent = new Intent(_intent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Setting Intent of " + this + " to target " + targetIntent);
+ ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to target %s", this, targetIntent);
intent = targetIntent;
realActivity = targetComponent;
origActivity = _intent.getComponent();
@@ -2376,6 +2370,7 @@
private void initializeChangeTransition(Rect startBounds) {
mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
+ mAtmService.getTransitionController().collect(this);
mDisplayContent.mChangingContainers.add(this);
mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
@@ -4063,17 +4058,20 @@
info.topActivityType = top.getActivityType();
info.isResizeable = isResizeable();
- ActivityRecord rootActivity = top.getRootActivity();
- if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) {
- info.pictureInPictureParams = null;
- } else {
- info.pictureInPictureParams = rootActivity.pictureInPictureArgs;
- }
+ info.pictureInPictureParams = getPictureInPictureParams();
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
: null;
}
+ @Nullable PictureInPictureParams getPictureInPictureParams() {
+ final Task top = getTopMostTask();
+ if (top == null) return null;
+ final ActivityRecord rootActivity = top.getRootActivity();
+ return (rootActivity == null || rootActivity.pictureInPictureArgs.empty())
+ ? null : rootActivity.pictureInPictureArgs;
+ }
+
/**
* Returns a {@link TaskInfo} with information from this task.
*/
@@ -4766,6 +4764,16 @@
}
@Override
+ boolean showSurfaceOnCreation() {
+ // Organized tasks handle their own surface visibility
+ final boolean willBeOrganized =
+ mAtmService.mTaskOrganizerController.isSupportedWindowingMode(getWindowingMode())
+ && isRootTask();
+ return !mAtmService.getTransitionController().isShellTransitionsEnabled()
+ || !willBeOrganized;
+ }
+
+ @Override
protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
/**
* Avoid reparenting SurfaceControl of the organized tasks that are always on top, since
@@ -4785,7 +4793,9 @@
// hide it to allow the task organizer to show it when it is properly reparented. We
// skip this for tasks created by the organizer because they can synchronously update
// the leash before new children are added to the task.
- if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) {
+ if (!mAtmService.getTransitionController().isShellTransitionsEnabled()
+ && !mCreatedByOrganizer
+ && mTaskOrganizer != null && !prevHasBeenVisible) {
getSyncTransaction().hide(getSurfaceControl());
commitPendingTransaction();
}
@@ -5304,8 +5314,8 @@
}
void minimalResumeActivityLocked(ActivityRecord r) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
- + " callers=" + Debug.getCallers(5));
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (starting new instance) "
+ + "callers=%s", r, Debug.getCallers(5));
r.setState(RESUMED, "minimalResumeActivityLocked");
r.completeResumeLocked();
}
@@ -5349,7 +5359,7 @@
if (mResumedActivity != null) {
// Still have something resumed; can't sleep until it is paused.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
+ ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"Sleep => pause with userLeaving=false");
@@ -5358,15 +5368,15 @@
shouldSleep = false ;
} else if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
+ ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
shouldSleep = false;
}
if (!shuttingDown) {
if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
// Still need to tell some activities to stop; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
- + mStackSupervisor.mStoppingActivities.size() + " activities");
+ ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
+ mStackSupervisor.mStoppingActivities.size());
mStackSupervisor.scheduleIdle();
shouldSleep = false;
@@ -5445,8 +5455,7 @@
return false;
}
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
- else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = prev.isNoHistory() ? prev : null;
@@ -5477,13 +5486,13 @@
boolean didAutoPip = false;
if (prev.attachedToProcess()) {
if (shouldAutoPip) {
- if (DEBUG_PAUSE) {
- Slog.d(TAG_PAUSE, "Auto-PIP allowed, entering PIP mode directly: " + prev);
- }
+ ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+ + "directly: %s", prev);
+
didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
mPausingActivity = null;
} else {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
try {
EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving, reason);
@@ -5523,8 +5532,8 @@
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
- } else if (DEBUG_PAUSE) {
- Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
+ } else {
+ ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
}
if (pauseImmediately) {
@@ -5541,7 +5550,7 @@
} else {
// This activity failed to schedule the
// pause, so just treat it as being paused now.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
+ ProtoLog.v(WM_DEBUG_STATES, "Activity not running, resuming next.");
if (resuming == null) {
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
@@ -5552,22 +5561,22 @@
@VisibleForTesting
void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
if (prev != null) {
prev.setWillCloseOrEnterPip(false);
final boolean wasStopping = prev.isState(STOPPING);
prev.setState(PAUSED, "completePausedLocked");
if (prev.finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
prev = prev.completeFinishing("completePausedLocked");
} else if (prev.hasProcess()) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
- + " wasStopping=" + wasStopping
- + " visibleRequested=" + prev.mVisibleRequested);
+ ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
+ + "wasStopping=%b visibleRequested=%b", prev, wasStopping,
+ prev.mVisibleRequested);
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) {
// We are also stopping, the stop request must have gone soon after the pause.
@@ -5583,7 +5592,7 @@
"completePauseLocked");
}
} else {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
+ ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
prev = null;
}
// It is possible the activity was freezing the screen before it was paused.
@@ -5690,12 +5699,10 @@
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- mTopActivityOccludesKeyguard = false;
- mTopDismissingKeyguardActivity = null;
- mTopTurnScreenOnActivity = null;
mStackSupervisor.beginActivityVisibilityUpdate();
try {
- mEnsureActivitiesVisibleHelper.processUpdate(starting);
+ mEnsureActivitiesVisibleHelper.process(starting, configChanges, preserveWindows,
+ notifyClients);
if (mTranslucentActivityWaiting != null &&
mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
@@ -5704,24 +5711,10 @@
notifyActivityDrawnLocked(null);
}
} finally {
- mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges, preserveWindows,
- notifyClients);
+ mStackSupervisor.endActivityVisibilityUpdate();
}
}
- void commitActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
- mEnsureActivitiesVisibleHelper.processCommit(starting, configChanges, preserveWindows,
- notifyClients);
- }
-
- /**
- * @return true if the top visible activity wants to occlude the Keyguard, false otherwise
- */
- boolean topActivityOccludesKeyguard() {
- return mTopActivityOccludesKeyguard;
- }
-
/**
* Returns true if this stack should be resized to match the bounds specified by
* {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack.
@@ -5740,44 +5733,6 @@
&& this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode());
}
- /**
- * @return the top most visible activity that wants to dismiss Keyguard
- */
- ActivityRecord getTopDismissingKeyguardActivity() {
- return mTopDismissingKeyguardActivity;
- }
-
- /**
- * @return the top most visible activity that wants to turn screen on
- */
- ActivityRecord getTopTurnScreenOnActivity() {
- return mTopTurnScreenOnActivity;
- }
-
- /**
- * Updates {@link #mTopActivityOccludesKeyguard}, {@link #mTopTurnScreenOnActivity} and
- * {@link #mTopDismissingKeyguardActivity} if this task could be visible.
- *
- */
- void updateKeyguardVisibility(ActivityRecord r, boolean isTop) {
- final boolean showWhenLocked = r.canShowWhenLocked();
- final boolean dismissKeyguard = r.containsDismissKeyguardWindow();
- final boolean turnScreenOn = r.canTurnScreenOn();
- if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
- mTopDismissingKeyguardActivity = r;
- }
-
- if (turnScreenOn && mTopTurnScreenOnActivity == null) {
- mTopTurnScreenOnActivity = r;
- }
-
- // Only the top activity may control occluded, as we can't occlude the Keyguard if the
- // top app doesn't want to occlude it.
- if (isTop) {
- mTopActivityOccludesKeyguard |= showWhenLocked;
- }
- }
-
void checkTranslucentActivityWaiting(ActivityRecord top) {
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -5933,8 +5888,8 @@
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Top activity resumed " + next);
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
+ + "resumed %s", next);
return false;
}
@@ -5945,9 +5900,9 @@
// If we are currently pausing an activity, then don't do anything until that is done.
final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
if (!allPausedComplete) {
- if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) {
- Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing.");
- }
+ ProtoLog.v(WM_DEBUG_STATES,
+ "resumeTopActivityLocked: Skip resume: some activity pausing.");
+
return false;
}
@@ -5959,8 +5914,8 @@
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Going to sleep and all paused");
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and"
+ + " all paused");
return false;
}
@@ -5982,7 +5937,7 @@
// If we are currently pausing an activity, then don't do anything until that is done.
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
- if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
+ ProtoLog.v(WM_DEBUG_STATES,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
return false;
@@ -6008,14 +5963,13 @@
boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next);
if (mResumedActivity != null) {
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Pausing " + mResumedActivity);
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next,
- "resumeTopActivityInnerLocked");
+ "resumeTopActivityInnerLocked");
}
if (pausing) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
- "resumeTopActivityLocked: Skip resume: need to start pausing");
+ ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to"
+ + " start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
@@ -6044,8 +5998,8 @@
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed "
+ + "(dontWaitForPause) %s", next);
return true;
}
@@ -6055,8 +6009,8 @@
if (shouldSleepActivities() && mLastNoHistoryActivity != null
&& !mLastNoHistoryActivity.finishing
&& mLastNoHistoryActivity != next) {
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "no-history finish of " + mLastNoHistoryActivity + " on new resume");
+ ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s on new resume",
+ mLastNoHistoryActivity);
mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);
mLastNoHistoryActivity = null;
}
@@ -6175,8 +6129,7 @@
mAtmService.updateCpuStats();
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
- + " (in existing)");
+ ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
next.setState(RESUMED, "resumeTopActivityInnerLocked");
@@ -6206,9 +6159,8 @@
// is still at the top and schedule another run if something
// weird happened.
ActivityRecord nextNext = topRunningActivity();
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
- "Activity config changed during resume: " + next
- + ", new next: " + nextNext);
+ ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
+ + "%s, new next: %s", next, nextNext);
if (nextNext != next) {
// Do over!
mStackSupervisor.scheduleResumeTopActivities();
@@ -6255,12 +6207,11 @@
dc.isNextTransitionForward()));
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
- if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
- + next);
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next);
} catch (Exception e) {
// Whoops, need to restart this activity!
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
- + lastState + ": " + next);
+ ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+ + "%s", lastState, next);
next.setState(lastState, "resumeTopActivityInnerLocked");
// lastResumedActivity being non-null implies there is a lastStack present.
@@ -6302,7 +6253,7 @@
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
- if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
+ ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next);
mStackSupervisor.startSpecificActivity(next, true, true);
}
@@ -6334,8 +6285,8 @@
// If the current stack is a home stack, or if focus didn't switch to a different stack -
// just start up the Launcher...
ActivityOptions.abort(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home");
+ ProtoLog.d(WM_DEBUG_STATES, "resumeNextFocusableActivityWhenStackIsEmpty: %s, "
+ + "go home", reason);
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
}
@@ -6420,7 +6371,15 @@
transit = TRANSIT_TASK_OPEN;
}
}
- dc.prepareAppTransition(transit, keepCurTransition);
+ if (mAtmService.getTransitionController().isShellTransitionsEnabled()
+ // TODO(shell-transitions): eventually all transitions.
+ && transit == TRANSIT_TASK_OPEN) {
+ Transition transition =
+ mAtmService.getTransitionController().requestTransition(transit);
+ transition.collect(task);
+ } else {
+ dc.prepareAppTransition(transit, keepCurTransition);
+ }
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
@@ -7055,8 +7014,8 @@
boolean handleAppDied(WindowProcessController app) {
boolean isPausingDied = false;
if (mPausingActivity != null && mPausingActivity.app == app) {
- if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
- "App died while pausing: " + mPausingActivity);
+ ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
+ mPausingActivity);
mPausingActivity = null;
isPausingDied = true;
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 55e6a78..ce99102 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -33,12 +33,10 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
import static com.android.server.wm.DisplayContent.alwaysCreateStack;
-import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -212,11 +210,13 @@
return mChildren.indexOf(task);
}
- @Nullable Task getRootHomeTask() {
+ @Nullable
+ Task getRootHomeTask() {
return mRootHomeTask;
}
- @Nullable Task getRootRecentsTask() {
+ @Nullable
+ Task getRootRecentsTask() {
return mRootRecentsTask;
}
@@ -526,19 +526,20 @@
* When stack is added or repositioned, find a proper position for it.
*
* The order is defined as:
- * - Dream is on top of everything
- * - PiP is directly below the Dream
- * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
- * existing ones
- * - other non-always-on-top stacks come directly below always-on-top stacks; new
- * non-always-on-top stacks are added directly below always-on-top stacks and above existing
- * non-always-on-top stacks
- * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
- * (including the Dream); otherwise, it is a normal non-always-on-top stack
+ * - Dream is on top of everything
+ * - PiP is directly below the Dream
+ * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
+ * existing ones
+ * - other non-always-on-top stacks come directly below always-on-top stacks; new
+ * non-always-on-top stacks are added directly below always-on-top stacks and above existing
+ * non-always-on-top stacks
+ * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
+ * (including the Dream); otherwise, it is a normal non-always-on-top stack
*
* @param requestedPosition Position requested by caller.
- * @param stack Stack to be added or positioned.
- * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
+ * @param stack Stack to be added or positioned.
+ * @param adding Flag indicates whether we're adding a new stack or positioning an
+ * existing.
* @return The proper position for the stack.
*/
private int findPositionForStack(int requestedPosition, Task stack, boolean adding) {
@@ -655,6 +656,7 @@
/**
* Sets whether the task display area should ignore fixed-orientation request from apps.
+ *
* @return Whether the display orientation changed
*/
boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
@@ -774,7 +776,7 @@
* Adjusts the layer of the stack which belongs to the same group.
* Note that there are three stack groups: home stacks, always on top stacks, and normal stacks.
*
- * @param startLayer The beginning layer of this group of stacks.
+ * @param startLayer The beginning layer of this group of stacks.
* @param normalStacks Set {@code true} if this group is neither home nor always on top.
* @return The adjusted layer value.
*/
@@ -921,6 +923,7 @@
/**
* Returns an existing stack compatible with the windowing mode and activity type or creates one
* if a compatible stack doesn't exist.
+ *
* @see #getOrCreateStack(int, int, boolean, Intent, Task)
*/
Task getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
@@ -933,6 +936,7 @@
* existing compatible root task or creates a new one.
* For one level task, the candidate task would be reused to also be the root task or create
* a new root task if no candidate task.
+ *
* @see #getStack(int, int)
* @see #createStack(int, int, boolean)
*/
@@ -978,6 +982,7 @@
/**
* Returns an existing stack compatible with the input params or creates one
* if a compatible stack doesn't exist.
+ *
* @see #getOrCreateStack(int, int, boolean)
*/
Task getOrCreateStack(@Nullable ActivityRecord r,
@@ -1006,17 +1011,21 @@
/**
* Creates a stack matching the input windowing mode and activity type on this display.
- * @param windowingMode The windowing mode the stack should be created in. If
- * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
- * inherit its parent's windowing mode.
- * @param activityType The activityType the stack should be created in. If
- * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
- * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
- * @param onTop If true the stack will be created at the top of the display, else at the bottom.
- * @param info The started activity info.
- * @param intent The intent that started this task.
+ *
+ * @param windowingMode The windowing mode the stack should be created in. If
+ * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack
+ * will
+ * inherit its parent's windowing mode.
+ * @param activityType The activityType the stack should be created in. If
+ * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack
+ * will
+ * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ * @param onTop If true the stack will be created at the top of the display, else
+ * at the bottom.
+ * @param info The started activity info.
+ * @param intent The intent that started this task.
* @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
- * otherwise.
+ * otherwise.
* @return The newly created stack.
*/
Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
@@ -1223,8 +1232,9 @@
* paused in stacks that are no longer visible or in pinned windowing mode. This does not
* pause activities in visible stacks, so if an activity is launched within the same stack/task,
* then we should explicitly pause that stack's top activity.
+ *
* @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
- * @param resuming The resuming activity.
+ * @param resuming The resuming activity.
* @return {@code true} if any activity was paused as a result of this call.
*/
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
@@ -1235,10 +1245,8 @@
if (resumedActivity != null
&& (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
|| !stack.isTopActivityFocusable())) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
- + " mResumedActivity=" + resumedActivity);
- }
+ ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: stack=%s "
+ + "mResumedActivity=%s", stack, resumedActivity);
someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
resuming, "pauseBackStacks");
}
@@ -1255,9 +1263,8 @@
for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final Task stack = getStackAt(stackNdx);
if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
- if (DEBUG_TASKS) {
- Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
- }
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) "
+ + "%s", stack);
continue;
}
@@ -1298,10 +1305,9 @@
final int windowingMode = windowingModes[j];
for (int i = getStackCount() - 1; i >= 0; --i) {
final Task stack = getStackAt(i);
- if (!stack.isActivityTypeStandardOrUndefined()) {
- continue;
- }
- if (stack.getWindowingMode() != windowingMode) {
+ if (stack.mCreatedByOrganizer
+ || !stack.isActivityTypeStandardOrUndefined()
+ || stack.getWindowingMode() != windowingMode) {
continue;
}
stacks.add(stack);
@@ -1400,12 +1406,13 @@
/**
* Returns true if the {@param windowingMode} is supported based on other parameters passed in.
- * @param windowingMode The windowing mode we are checking support for.
+ *
+ * @param windowingMode The windowing mode we are checking support for.
* @param supportsMultiWindow If we should consider support for multi-window mode in general.
* @param supportsSplitScreen If we should consider support for split-screen multi-window.
- * @param supportsFreeform If we should consider support for freeform multi-window.
- * @param supportsPip If we should consider support for picture-in-picture mutli-window.
- * @param activityType The activity type under consideration.
+ * @param supportsFreeform If we should consider support for freeform multi-window.
+ * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+ * @param activityType The activity type under consideration.
* @return true if the windowing mode is supported.
*/
private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
@@ -1444,9 +1451,9 @@
* Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
* display with the provided parameters.
*
- * @param r The ActivityRecord in question.
- * @param options Options to start with.
- * @param task The task within-which the activity would start.
+ * @param r The ActivityRecord in question.
+ * @param options Options to start with.
+ * @param task The task within-which the activity would start.
* @param activityType The type of activity to start.
* @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
*/
@@ -1481,9 +1488,9 @@
* on this display.
*
* @param windowingMode The windowing-mode to validate.
- * @param r The {@link ActivityRecord} to check against.
- * @param task The {@link Task} to check against.
- * @param activityType An activity type.
+ * @param r The {@link ActivityRecord} to check against.
+ * @param task The {@link Task} to check against.
+ * @param activityType An activity type.
* @return {@code true} if windowingMode is valid, {@code false} otherwise.
*/
boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
@@ -1508,7 +1515,7 @@
return windowingMode != WINDOWING_MODE_UNDEFINED
&& isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
- supportsFreeform, supportsPip, activityType);
+ supportsFreeform, supportsPip, activityType);
}
/**
@@ -1516,9 +1523,9 @@
* on this display.
*
* @param windowingMode The windowing-mode to validate.
- * @param r The {@link ActivityRecord} to check against.
- * @param task The {@link Task} to check against.
- * @param activityType An activity type.
+ * @param r The {@link ActivityRecord} to check against.
+ * @param task The {@link Task} to check against.
+ * @param activityType An activity type.
* @return The provided windowingMode or the closest valid mode which is appropriate.
*/
int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
@@ -1541,20 +1548,6 @@
return stack == getTopStack();
}
- boolean isTopNotFinishNotPinnedStack(Task stack) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task current = getStackAt(i);
- final ActivityRecord topAct = current.getTopNonFinishingActivity();
- if (topAct == null) {
- continue;
- }
- if (!current.inPinnedWindowingMode()) {
- return current == stack;
- }
- }
- return false;
- }
-
ActivityRecord topRunningActivity() {
return topRunningActivity(false /* considerKeyguardState */);
}
@@ -1620,6 +1613,7 @@
/**
* Returns the existing home stack or creates and returns a new one if it should exist for the
* display.
+ *
* @param onTop Only be used when there is no existing home stack. If true the home stack will
* be created at the top of the display, else at the bottom.
*/
@@ -1757,7 +1751,7 @@
/**
* @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
- * already top-most.
+ * already top-most.
*/
static Task getStackAbove(Task stack) {
final WindowContainer wc = stack.getParent();
@@ -1803,6 +1797,7 @@
/**
* Notifies of a stack order change
+ *
* @param stack The stack which triggered the order change
*/
void onStackOrderChanged(Task stack) {
@@ -1833,8 +1828,7 @@
notifyClients);
}
} finally {
- mAtmService.mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges,
- preserveWindows, notifyClients);
+ mAtmService.mStackSupervisor.endActivityVisibilityUpdate();
}
}
@@ -1847,6 +1841,7 @@
/**
* Removes the stacks in the node applying the content removal node from the display.
+ *
* @return last reparented stack, or {@code null} if the stacks had to be destroyed.
*/
Task remove() {
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index e07c567..8201d10 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -354,7 +354,7 @@
: null;
}
- private boolean isSupportedWindowingMode(int winMode) {
+ boolean isSupportedWindowingMode(int winMode) {
return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
new file mode 100644
index 0000000..fc67cd2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -0,0 +1,487 @@
+/*
+ * 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.wm;
+
+
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.Display;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.window.TransitionInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.ProtoLogGroup;
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents a logical transition.
+ * @see TransitionController
+ */
+class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListener {
+ private static final String TAG = "Transition";
+
+ /** The transition has been created and is collecting, but hasn't formally started. */
+ private static final int STATE_COLLECTING = 0;
+
+ /**
+ * The transition has formally started. It is still collecting but will stop once all
+ * participants are ready to animate (finished drawing).
+ */
+ private static final int STATE_STARTED = 1;
+
+ /**
+ * This transition is currently playing its animation and can no longer collect or be changed.
+ */
+ private static final int STATE_PLAYING = 2;
+
+ final @WindowManager.TransitionType int mType;
+ private int mSyncId;
+ private @WindowManager.TransitionFlags int mFlags;
+ private final TransitionController mController;
+ final ArrayMap<WindowContainer, ChangeInfo> mParticipants = new ArrayMap<>();
+ private int mState = STATE_COLLECTING;
+ private boolean mReadyCalled = false;
+
+ Transition(@WindowManager.TransitionType int type,
+ @WindowManager.TransitionFlags int flags, TransitionController controller) {
+ mType = type;
+ mFlags = flags;
+ mController = controller;
+ mSyncId = mController.mSyncEngine.startSyncSet(this);
+ }
+
+ /**
+ * Formally starts the transition. Participants can be collected before this is started,
+ * but this won't consider itself ready until started -- even if all the participants have
+ * drawn.
+ */
+ void start() {
+ if (mState >= STATE_STARTED) {
+ Slog.w(TAG, "Transition already started: " + mSyncId);
+ }
+ mState = STATE_STARTED;
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
+ mSyncId);
+ if (mReadyCalled) {
+ setReady();
+ }
+ }
+
+ /** Adds wc to set of WindowContainers participating in this transition. */
+ void collect(@NonNull WindowContainer wc) {
+ if (mSyncId < 0) return;
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Collecting in transition %d: %s",
+ mSyncId, wc);
+ // Add to sync set before checking contains because it may not have added it at other
+ // times (eg. if wc was previously invisible).
+ mController.mSyncEngine.addToSyncSet(mSyncId, wc);
+ if (mParticipants.containsKey(wc)) return;
+ mParticipants.put(wc, new ChangeInfo());
+ }
+
+ /**
+ * Call this when all known changes related to this transition have been applied. Until
+ * all participants have finished drawing, the transition can still collect participants.
+ *
+ * If this is called before the transition is started, it will be deferred until start.
+ */
+ void setReady() {
+ if (mSyncId < 0) return;
+ if (mState < STATE_STARTED) {
+ mReadyCalled = true;
+ return;
+ }
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Finish collecting in transition %d", mSyncId);
+ mController.mSyncEngine.setReady(mSyncId);
+ mController.mAtm.mWindowManager.mWindowPlacerLocked.requestTraversal();
+ }
+
+ /** The transition has finished animating and is ready to finalize WM state */
+ void finishTransition() {
+ if (mState < STATE_PLAYING) {
+ throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
+ }
+ for (int i = 0; i < mParticipants.size(); ++i) {
+ final ActivityRecord ar = mParticipants.keyAt(i).asActivityRecord();
+ if (ar == null || ar.mVisibleRequested) {
+ continue;
+ }
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Commit activity becoming invisible: %s", ar);
+ ar.commitVisibility(false /* visible */, false /* performLayout */);
+ }
+ }
+
+ @Override
+ public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
+ if (syncId != mSyncId) {
+ Slog.e(TAG, "Unexpected Sync ID " + syncId + ". Expected " + mSyncId);
+ return;
+ }
+ mState = STATE_PLAYING;
+ mController.moveToPlaying(this);
+ final TransitionInfo info = calculateTransitionInfo(mType, mParticipants);
+
+ SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
+ int displayId = Display.DEFAULT_DISPLAY;
+ for (WindowContainer container : windowContainersReady) {
+ container.mergeBlastSyncTransaction(mergedTransaction);
+ displayId = container.mDisplayContent.getDisplayId();
+ }
+
+ handleNonAppWindowsInTransition(displayId, mType, mFlags);
+
+ if (mController.getTransitionPlayer() != null) {
+ try {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Calling onTransitionReady: %s", info);
+ mController.getTransitionPlayer().onTransitionReady(this, info, mergedTransaction);
+ } catch (RemoteException e) {
+ // If there's an exception when trying to send the mergedTransaction to the
+ // client, we should immediately apply it here so the transactions aren't lost.
+ mergedTransaction.apply();
+ }
+ } else {
+ mergedTransaction.apply();
+ }
+ mSyncId = -1;
+ }
+
+ private void handleNonAppWindowsInTransition(int displayId, int transit, int flags) {
+ final DisplayContent dc =
+ mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
+ if (dc == null) {
+ return;
+ }
+ if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+ if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
+ Animation anim = mController.mAtm.mWindowManager.mPolicy
+ .createKeyguardWallpaperExit(
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+ if (anim != null) {
+ anim.scaleCurrentDuration(
+ mController.mAtm.mWindowManager.getTransitionAnimationScaleLocked());
+ dc.mWallpaperController.startWallpaperAnimation(anim);
+ }
+ }
+ }
+ if (transit == TRANSIT_KEYGUARD_GOING_AWAY
+ || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+ dc.startKeyguardExitOnNonAppWindows(
+ transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
+ mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(transit, 0);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("TransitionRecord{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" id=" + mSyncId);
+ sb.append(" type=" + mType);
+ sb.append(" flags=" + mFlags);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ private static boolean reportIfNotTop(WindowContainer wc) {
+ // Organized tasks need to be reported anyways because Core won't show() their surfaces
+ // and we can't rely on onTaskAppeared because it isn't in sync.
+ // TODO(shell-transitions): switch onTaskAppeared usage over to transitions OPEN.
+ return wc.isOrganized();
+ }
+
+ /** @return the depth of child within ancestor, 0 if child == ancestor, or -1 if not a child. */
+ private static int getChildDepth(WindowContainer child, WindowContainer ancestor) {
+ WindowContainer parent = child;
+ int depth = 0;
+ while (parent != null) {
+ if (parent == ancestor) {
+ return depth;
+ }
+ parent = parent.getParent();
+ ++depth;
+ }
+ return -1;
+ }
+
+ private static @TransitionInfo.TransitionMode int getModeFor(WindowContainer wc) {
+ if (wc.isVisibleRequested()) {
+ final Task t = wc.asTask();
+ if (t != null && t.getHasBeenVisible()) {
+ return TransitionInfo.TRANSIT_SHOW;
+ }
+ return TransitionInfo.TRANSIT_OPEN;
+ }
+ return TransitionInfo.TRANSIT_CLOSE;
+ }
+
+ /**
+ * 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
+ * animation can play just on the parent rather than all the individual children.
+ *
+ * @return {@code true} if transition in target can be promoted to its parent.
+ */
+ private static boolean canPromote(
+ WindowContainer target, ArraySet<WindowContainer> topTargets) {
+ final WindowContainer parent = target.getParent();
+ if (parent == null || !parent.canCreateRemoteAnimationTarget()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " SKIP: %s",
+ parent == null ? "no parent" : ("parent can't be target " + parent));
+ return false;
+ }
+ @TransitionInfo.TransitionMode int mode = TransitionInfo.TRANSIT_NONE;
+ // Go through all siblings of this target to see if any of them would prevent
+ // the target from promoting.
+ siblingLoop:
+ for (int i = parent.getChildCount() - 1; i >= 0; --i) {
+ final WindowContainer sibling = parent.getChildAt(i);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " check sibling %s",
+ sibling);
+ // Check if any topTargets are the sibling or within it
+ for (int j = topTargets.size() - 1; j >= 0; --j) {
+ final int depth = getChildDepth(topTargets.valueAt(j), sibling);
+ if (depth < 0) continue;
+ if (depth == 0) {
+ final int siblingMode = sibling.isVisibleRequested()
+ ? TransitionInfo.TRANSIT_OPEN : TransitionInfo.TRANSIT_CLOSE;
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " sibling is a top target with mode %s",
+ TransitionInfo.modeToString(siblingMode));
+ if (mode == TransitionInfo.TRANSIT_NONE) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " no common mode yet, so set it");
+ mode = siblingMode;
+ } else if (mode != siblingMode) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " SKIP: common mode mismatch. was %s",
+ TransitionInfo.modeToString(mode));
+ return false;
+ }
+ continue siblingLoop;
+ } else {
+ // Sibling subtree may not be promotable.
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " SKIP: sibling contains top target %s",
+ topTargets.valueAt(j));
+ return false;
+ }
+ }
+ // No other animations are playing in this sibling
+ if (sibling.isVisibleRequested()) {
+ // Sibling is visible but not animating, so no promote.
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " SKIP: sibling is visible but not part of transition");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Go through topTargets and try to promote (see {@link #canPromote}) one of them.
+ *
+ * @param topTargets set of just the top-most targets in the hierarchy of participants.
+ * @param targets all targets that will be sent to the player.
+ * @return {@code true} if something was promoted.
+ */
+ private static boolean tryPromote(ArraySet<WindowContainer> topTargets,
+ ArrayMap<WindowContainer, ChangeInfo> targets) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " --- Start combine pass ---");
+ // Go through each target until we find one that can be promoted.
+ targetLoop:
+ for (WindowContainer targ : topTargets) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " checking %s", targ);
+ if (!canPromote(targ, topTargets)) {
+ continue;
+ }
+ final WindowContainer parent = targ.getParent();
+ // No obstructions found to promotion, so promote
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " CAN PROMOTE: promoting to parent %s", parent);
+ final ChangeInfo parentInfo = new ChangeInfo();
+ targets.put(parent, parentInfo);
+ // Go through all children of newly-promoted container and remove them from
+ // the top-targets.
+ for (int i = parent.getChildCount() - 1; i >= 0; --i) {
+ final WindowContainer child = parent.getChildAt(i);
+ int idx = targets.indexOfKey(child);
+ if (idx >= 0) {
+ if (reportIfNotTop(child)) {
+ targets.valueAt(idx).mParent = parent;
+ parentInfo.addChild(child);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " keep as target %s", child);
+ } else {
+ if (targets.valueAt(idx).mChildren != null) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " merging children in from %s: %s", child,
+ targets.valueAt(idx).mChildren);
+ parentInfo.addChildren(targets.valueAt(idx).mChildren);
+ }
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " remove from targets %s", child);
+ targets.removeAt(idx);
+ }
+ }
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " remove from topTargets %s", child);
+ topTargets.remove(child);
+ }
+ topTargets.add(parent);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Find WindowContainers to be animated from a set of opening and closing apps. We will promote
+ * animation targets to higher level in the window hierarchy if possible.
+ */
+ @VisibleForTesting
+ static TransitionInfo calculateTransitionInfo(
+ int type, Map<WindowContainer, ChangeInfo> participants) {
+ final TransitionInfo out = new TransitionInfo(type);
+
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Start calculating TransitionInfo based on participants: %s",
+ new ArraySet<>(participants.keySet()));
+
+ final ArraySet<WindowContainer> topTargets = new ArraySet<>();
+ // The final animation targets which cannot promote to higher level anymore.
+ final ArrayMap<WindowContainer, ChangeInfo> targets = new ArrayMap<>();
+
+ final ArrayList<WindowContainer> tmpList = new ArrayList<>();
+
+ // Build initial set of top-level participants by removing any participants that are
+ // children of other participants or are otherwise invalid.
+ for (Map.Entry<WindowContainer, ChangeInfo> entry : participants.entrySet()) {
+ final WindowContainer wc = entry.getKey();
+ // Don't include detached windows.
+ if (!wc.isAttached()) continue;
+
+ final ChangeInfo changeInfo = entry.getValue();
+ WindowContainer parent = wc.getParent();
+ WindowContainer topParent = null;
+ // Keep track of always-report parents in bottom-to-top order
+ tmpList.clear();
+ while (parent != null) {
+ if (participants.containsKey(parent)) {
+ topParent = parent;
+ } else if (reportIfNotTop(parent)) {
+ tmpList.add(parent);
+ }
+ parent = parent.getParent();
+ }
+ if (topParent != null) {
+ // Add always-report parents along the way
+ parent = topParent;
+ for (int i = tmpList.size() - 1; i >= 0; --i) {
+ if (!participants.containsKey(tmpList.get(i))) {
+ final ChangeInfo info = new ChangeInfo();
+ info.mParent = parent;
+ targets.put(tmpList.get(i), info);
+ }
+ parent = tmpList.get(i);
+ }
+ continue;
+ }
+ targets.put(wc, changeInfo);
+ topTargets.add(wc);
+ }
+
+ // Populate children lists
+ for (int i = targets.size() - 1; i >= 0; --i) {
+ if (targets.valueAt(i).mParent != null) {
+ targets.get(targets.valueAt(i).mParent).addChild(targets.keyAt(i));
+ }
+ }
+
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Initial targets: %s", new ArraySet<>(targets.keySet()));
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Top targets: %s", topTargets);
+
+ // Combine targets by repeatedly going through the topTargets to see if they can be
+ // promoted until there aren't any promotions possible.
+ while (tryPromote(topTargets, targets)) {
+ // Empty on purpose
+ }
+
+ // Convert all the resolved ChangeInfos into a TransactionInfo object.
+ for (int i = targets.size() - 1; i >= 0; --i) {
+ final WindowContainer target = targets.keyAt(i);
+ final ChangeInfo info = targets.valueAt(i);
+ final TransitionInfo.Change change = new TransitionInfo.Change(
+ target.mRemoteToken.toWindowContainerToken(), target.getSurfaceControl());
+ if (info.mParent != null) {
+ change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
+ }
+ change.setMode(getModeFor(target));
+ out.addChange(change);
+ }
+
+ return out;
+ }
+
+ static Transition fromBinder(IBinder binder) {
+ return (Transition) binder;
+ }
+
+ @VisibleForTesting
+ static class ChangeInfo {
+ WindowContainer mParent;
+ ArraySet<WindowContainer> mChildren;
+ // TODO(shell-transitions): other tracking like before state and bounds
+ void addChild(@NonNull WindowContainer wc) {
+ if (mChildren == null) {
+ mChildren = new ArraySet<>();
+ }
+ mChildren.add(wc);
+ }
+ void addChildren(@NonNull ArraySet<WindowContainer> wcs) {
+ if (mChildren == null) {
+ mChildren = new ArraySet<>();
+ }
+ mChildren.addAll(wcs);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
new file mode 100644
index 0000000..d102c19
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -0,0 +1,225 @@
+/*
+ * 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.wm;
+
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
+import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.WindowManager;
+import android.window.ITransitionPlayer;
+
+import com.android.internal.protolog.ProtoLogGroup;
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Handles all the aspects of recording and synchronizing transitions.
+ */
+class TransitionController {
+ private static final String TAG = "TransitionController";
+
+ private static final int[] SUPPORTED_LEGACY_TRANSIT_TYPES = {TRANSIT_TASK_OPEN,
+ TRANSIT_TASK_CLOSE, TRANSIT_TASK_TO_FRONT, TRANSIT_TASK_TO_BACK,
+ TRANSIT_TASK_OPEN_BEHIND, TRANSIT_KEYGUARD_GOING_AWAY};
+ static {
+ Arrays.sort(SUPPORTED_LEGACY_TRANSIT_TYPES);
+ }
+
+ final BLASTSyncEngine mSyncEngine = new BLASTSyncEngine();
+ private ITransitionPlayer mTransitionPlayer;
+ private final IBinder.DeathRecipient mTransitionPlayerDeath = () -> mTransitionPlayer = null;
+ final ActivityTaskManagerService mAtm;
+
+ /** Currently playing transitions. When finished, records are removed from this list. */
+ private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>();
+
+ /**
+ * The transition currently being constructed (collecting participants).
+ * TODO(shell-transitions): When simultaneous transitions are supported, merge this with
+ * mPlayingTransitions.
+ */
+ private Transition mCollectingTransition = null;
+
+ TransitionController(ActivityTaskManagerService atm) {
+ mAtm = atm;
+ }
+
+ /** @see #createTransition(int, int) */
+ @NonNull
+ Transition createTransition(int type) {
+ return createTransition(type, 0 /* flags */);
+ }
+
+ /**
+ * Creates a transition. It can immediately collect participants.
+ */
+ @NonNull
+ Transition createTransition(@WindowManager.TransitionType int type,
+ @WindowManager.TransitionFlags int flags) {
+ if (mCollectingTransition != null) {
+ throw new IllegalStateException("Simultaneous transitions not supported yet.");
+ }
+ mCollectingTransition = new Transition(type, flags, this);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating Transition: %s",
+ mCollectingTransition);
+ return mCollectingTransition;
+ }
+
+ void registerTransitionPlayer(@Nullable ITransitionPlayer player) {
+ try {
+ if (mTransitionPlayer != null) {
+ mTransitionPlayer.asBinder().unlinkToDeath(mTransitionPlayerDeath, 0);
+ mTransitionPlayer = null;
+ }
+ player.asBinder().linkToDeath(mTransitionPlayerDeath, 0);
+ mTransitionPlayer = player;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to set transition player");
+ }
+ }
+
+ @Nullable ITransitionPlayer getTransitionPlayer() {
+ return mTransitionPlayer;
+ }
+
+ boolean isShellTransitionsEnabled() {
+ return mTransitionPlayer != null;
+ }
+
+ /** @return {@code true} if a transition is running */
+ boolean inTransition() {
+ // TODO(shell-transitions): eventually properly support multiple
+ return mCollectingTransition != null || !mPlayingTransitions.isEmpty();
+ }
+
+ /** @return {@code true} if wc is in a participant subtree */
+ boolean inTransition(@NonNull WindowContainer wc) {
+ if (mCollectingTransition != null && mCollectingTransition.mParticipants.containsKey(wc)) {
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ for (WindowContainer p = wc; p != null; p = p.getParent()) {
+ if (mPlayingTransitions.get(i).mParticipants.containsKey(p)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a transition and asks the TransitionPlayer (Shell) to start it.
+ * @return the created transition. Collection can start immediately.
+ */
+ @NonNull
+ Transition requestTransition(@WindowManager.TransitionType int type) {
+ return requestTransition(type, 0 /* flags */);
+ }
+
+ /** @see #requestTransition */
+ @NonNull
+ Transition requestTransition(@WindowManager.TransitionType int type,
+ @WindowManager.TransitionFlags int flags) {
+ if (mTransitionPlayer == null) {
+ throw new IllegalStateException("Shell Transitions not enabled");
+ }
+ final Transition transition = createTransition(type, flags);
+ try {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Requesting StartTransition: %s", transition);
+ mTransitionPlayer.requestStartTransition(type, transition);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error requesting transition", e);
+ transition.start();
+ }
+ return transition;
+ }
+
+ /**
+ * Temporary adapter that converts the legacy AppTransition's prepareAppTransition call into
+ * a Shell transition request. If shell transitions are enabled, this will take priority in
+ * handling transition types that it supports. All other transitions will be ignored and thus
+ * be handled by the legacy apptransition system. This allows both worlds to live in tandem
+ * during migration.
+ *
+ * @return {@code true} if the transition is handled.
+ */
+ boolean adaptLegacyPrepare(@WindowManager.TransitionType int transit,
+ @WindowManager.TransitionFlags int flags, boolean forceOverride) {
+ if (!isShellTransitionsEnabled()
+ || Arrays.binarySearch(SUPPORTED_LEGACY_TRANSIT_TYPES, transit) < 0) {
+ return false;
+ }
+ if (inTransition()) {
+ if (AppTransition.isKeyguardTransit(transit)) {
+ // TODO(shell-transitions): add to flags
+ } else if (forceOverride) {
+ // TODO(shell-transitions): sort out these flags
+ } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
+ // TODO(shell-transitions): record crashing
+ }
+ } else {
+ requestTransition(transit, flags);
+ }
+ return true;
+ }
+
+ /** @see Transition#collect */
+ void collect(@NonNull WindowContainer wc) {
+ if (mCollectingTransition == null) return;
+ mCollectingTransition.collect(wc);
+ }
+
+ /** @see Transition#setReady */
+ void setReady() {
+ if (mCollectingTransition == null) return;
+ mCollectingTransition.setReady();
+ }
+
+ /** @see Transition#finishTransition */
+ void finishTransition(@NonNull IBinder token) {
+ final Transition record = Transition.fromBinder(token);
+ if (record == null || !mPlayingTransitions.contains(record)) {
+ Slog.e(TAG, "Trying to finish a non-playing transition " + token);
+ return;
+ }
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Finish Transition: %s", record);
+ mPlayingTransitions.remove(record);
+ record.finishTransition();
+ }
+
+ void moveToPlaying(Transition transition) {
+ if (transition != mCollectingTransition) {
+ throw new IllegalStateException("Trying to move non-collecting transition to playing");
+ }
+ mCollectingTransition = null;
+ mPlayingTransitions.add(transition);
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 38bff9e..416b9df 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);
+ mWallpaperToken.getWindowConfiguration(), true, null, null, null);
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 5c6266a..ff5c174 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -103,7 +103,8 @@
mAnimationFrameCallback = frameTimeNs -> {
synchronized (mService.mGlobalLock) {
mAnimationFrameCallbackScheduled = false;
- animate(frameTimeNs);
+ final long vsyncId = mChoreographer.getVsyncId();
+ animate(frameTimeNs, vsyncId);
if (mNotifyWhenNoAnimation && !mLastRootAnimating) {
mService.mGlobalLock.notifyAll();
}
@@ -125,7 +126,7 @@
mInitialized = true;
}
- private void animate(long frameTimeNs) {
+ private void animate(long frameTimeNs, long vsyncId) {
if (!mInitialized) {
return;
}
@@ -133,6 +134,8 @@
// Schedule next frame already such that back-pressure happens continuously.
scheduleAnimation();
+ mTransaction.setFrameTimelineVsync(vsyncId);
+
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
if (DEBUG_WINDOW_TRACE) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 2b93080..38ec924 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -22,6 +22,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
+import static android.content.pm.ActivityInfo.reverseOrientation;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -417,7 +418,9 @@
void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
- getSyncTransaction().show(mSurfaceControl);
+ if (showSurfaceOnCreation()) {
+ getSyncTransaction().show(mSurfaceControl);
+ }
onSurfaceShown(getSyncTransaction());
updateSurfacePositionNonOrganized();
}
@@ -807,6 +810,13 @@
return parent != null ? parent.getDisplayArea() : null;
}
+ /** Get the first node of type {@link RootDisplayArea} above or at this node. */
+ @Nullable
+ RootDisplayArea getRootDisplayArea() {
+ WindowContainer parent = getParent();
+ return parent != null ? parent.getRootDisplayArea() : null;
+ }
+
boolean isAttached() {
return getDisplayArea() != null;
}
@@ -999,6 +1009,21 @@
}
/**
+ * Is this window's surface needed? This is almost like isVisible, except when participating
+ * in a transition, this will reflect the final visibility while isVisible won't change until
+ * the transition is finished.
+ */
+ boolean isVisibleRequested() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.isVisibleRequested()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Called when the visibility of a child is asked to change. This is before visibility actually
* changes (eg. a transition animation might play out first).
*/
@@ -1137,17 +1162,30 @@
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
int getRequestedConfigurationOrientation() {
- if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ int requestedOrientation = mOrientation;
+ final RootDisplayArea root = getRootDisplayArea();
+ if (root != null && root.isOrientationDifferentFromDisplay()) {
+ // Reverse the requested orientation if the orientation of its root is different from
+ // the display, so that when the display rotates to the reversed orientation, the
+ // requested app will be in the requested orientation.
+ // For example, if the display is 1200x900 (landscape), and the DAG is 600x900
+ // (portrait).
+ // When an app below the DAG is requesting landscape, it should actually request the
+ // display to be portrait, so that the DAG and the app will be in landscape.
+ requestedOrientation = reverseOrientation(mOrientation);
+ }
+
+ if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
// NOSENSOR means the display's "natural" orientation, so return that.
if (mDisplayContent != null) {
return mDisplayContent.getNaturalOrientation();
}
- } else if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// LOCKED means the activity's orientation remains unchanged, so return existing value.
return getConfiguration().orientation;
- } else if (isFixedOrientationLandscape(mOrientation)) {
+ } else if (isFixedOrientationLandscape(requestedOrientation)) {
return ORIENTATION_LANDSCAPE;
- } else if (isFixedOrientationPortrait(mOrientation)) {
+ } else if (isFixedOrientationPortrait(requestedOrientation)) {
return ORIENTATION_PORTRAIT;
}
return ORIENTATION_UNDEFINED;
@@ -2816,6 +2854,13 @@
return false;
}
+ /**
+ * @return {@code true} if this container's surface should be shown when it is created.
+ */
+ boolean showSurfaceOnCreation() {
+ return true;
+ }
+
static WindowContainer fromBinder(IBinder binder) {
return RemoteToken.fromBinder(binder).getContainer();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d434bf9..19cfcb2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -665,6 +665,8 @@
// Whether the system should use BLAST for ViewRootImpl
final boolean mUseBLAST;
+ // Whether to enable BLASTSyncEngine Transaction passing.
+ final boolean mUseBLASTSync = false;
int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Rect mDockedStackCreateBounds;
@@ -2129,7 +2131,7 @@
win.finishSeamlessRotation(false /* timeout */);
}
- if (win.useBLASTSync()) {
+ if (mUseBLASTSync && win.useBLASTSync()) {
result |= RELAYOUT_RES_BLAST_SYNC;
}
@@ -2460,7 +2462,10 @@
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
+ if (mAtmService.getTransitionController().inTransition(win)) {
+ focusMayChange = true;
+ win.mAnimatingExit = true;
+ } else if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
} else if (win.isAnimating(TRANSITION | PARENTS)) {
@@ -5127,6 +5132,10 @@
return mUseBLAST;
}
+ public boolean useBLASTSync() {
+ return mUseBLASTSync;
+ }
+
@Override
public void getInitialDisplaySize(int displayId, Point size) {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 999181d..f1641cd 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -26,6 +26,8 @@
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -40,6 +42,7 @@
import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskOrganizerController;
+import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowOrganizerController;
import android.window.WindowContainerToken;
@@ -88,21 +91,85 @@
final TaskOrganizerController mTaskOrganizerController;
final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
+ final TransitionController mTransitionController;
+
WindowOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
mGlobalLock = atm.mGlobalLock;
mTaskOrganizerController = new TaskOrganizerController(mService);
mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
+ mTransitionController = new TransitionController(atm);
+ }
+
+ TransitionController getTransitionController() {
+ return mTransitionController;
}
@Override
public void applyTransaction(WindowContainerTransaction t) {
- applySyncTransaction(t, null /*callback*/);
+ applyTransaction(t, null /*callback*/, null /*transition*/);
}
@Override
public int applySyncTransaction(WindowContainerTransaction t,
IWindowContainerTransactionCallback callback) {
+ return applyTransaction(t, callback, null /*transition*/);
+ }
+
+ @Override
+ public IBinder startTransition(int type, @Nullable IBinder transitionToken,
+ @Nullable WindowContainerTransaction t) {
+ enforceStackPermission("startTransition()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ Transition transition = Transition.fromBinder(transitionToken);
+ if (transition == null) {
+ if (type < 0) {
+ throw new IllegalArgumentException("Can't create transition with no type");
+ }
+ transition = mTransitionController.createTransition(type);
+ }
+ transition.start();
+ if (t == null) {
+ t = new WindowContainerTransaction();
+ }
+ applyTransaction(t, null /*callback*/, transition);
+ return transition;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public int finishTransition(@NonNull IBinder transitionToken,
+ @Nullable WindowContainerTransaction t,
+ @Nullable IWindowContainerTransactionCallback callback) {
+ enforceStackPermission("finishTransition()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ int syncId = -1;
+ if (t != null) {
+ syncId = applyTransaction(t, callback, null /*transition*/);
+ }
+ getTransitionController().finishTransition(transitionToken);
+ return syncId;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * @param callback If non-null, this will be a sync-transaction.
+ * @param transition A transition to collect changes into.
+ * @return a BLAST sync-id if this is a non-transition, sync transaction.
+ */
+ private int applyTransaction(@NonNull WindowContainerTransaction t,
+ @Nullable IWindowContainerTransactionCallback callback,
+ @Nullable Transition transition) {
enforceStackPermission("applySyncTransaction()");
int syncId = -1;
if (t == null) {
@@ -152,6 +219,7 @@
}
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
+ if (transition != null) transition.collect(wc);
effects |= containerEffect;
// Lifecycle changes will trigger ensureConfig for everything.
@@ -173,6 +241,12 @@
addToSyncSet(syncId, wc);
}
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ if (transition != null) {
+ transition.collect(wc);
+ if (hop.isReparent() && hop.getNewParent() != null) {
+ transition.collect(WindowContainer.fromBinder(hop.getNewParent()));
+ }
+ }
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
// this after hierarchy ops so we have the final organized state.
@@ -512,6 +586,19 @@
return true;
}
+ @Override
+ public void registerTransitionPlayer(ITransitionPlayer player) {
+ enforceStackPermission("registerTransitionPlayer()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ mTransitionController.registerTransitionPlayer(player);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void enforceStackPermission(String func) {
mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ad28177..8f42b3f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1683,6 +1683,11 @@
|| mControllableInsetProvider.isClientVisible());
}
+ @Override
+ boolean isVisibleRequested() {
+ return isVisible();
+ }
+
/**
* Ensures that all the policy visibility bits are set.
* @return {@code true} if all flags about visiblity are set
@@ -1771,7 +1776,7 @@
}
final ActivityRecord atoken = mActivityRecord;
if (atoken != null) {
- return ((!isParentWindowHidden() && atoken.mVisibleRequested)
+ return ((!isParentWindowHidden() && atoken.isVisible())
|| isAnimating(TRANSITION | PARENTS));
}
return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
@@ -5803,7 +5808,9 @@
}
mNotifyBlastOnSurfacePlacement = true;
- return mWinAnimator.finishDrawingLocked(null);
+ mWinAnimator.finishDrawingLocked(null);
+ // We always want to force a traversal after a finish draw for blast sync.
+ return true;
}
private void notifyBlastSyncTransaction() {
@@ -5814,6 +5821,15 @@
return;
}
+ final Task task = getTask();
+ if (task != null) {
+ final SurfaceControl.Transaction t = task.getMainWindowSizeChangeTransaction();
+ if (t != null) {
+ mBLASTSyncTransaction.merge(t);
+ }
+ task.setMainWindowSizeChangeTransaction(null);
+ }
+
// If localSyncId is >0 then we are syncing with children and will
// invoke transaction ready from our own #transactionReady callback
// we just need to signal our side of the sync (setReady). But if we
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2ace23f..13d8dc4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -23,12 +23,10 @@
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_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;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DRAW;
@@ -46,19 +44,16 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
-import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT;
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
-import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
@@ -365,7 +360,7 @@
if (mSurfaceController != null && mPendingDestroySurface != null) {
mPostDrawTransaction.reparentChildren(
mSurfaceController.getClientViewRootSurface(),
- mPendingDestroySurface.mSurfaceControl).apply();
+ mPendingDestroySurface.getClientViewRootSurface()).apply();
}
destroySurfaceLocked();
mSurfaceDestroyDeferred = true;
@@ -399,7 +394,7 @@
&& (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
mPostDrawTransaction.reparentChildren(
mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl).apply();
+ mSurfaceController.getClientViewRootSurface()).apply();
}
destroyDeferredSurfaceLocked();
@@ -636,6 +631,11 @@
}
private boolean shouldConsumeMainWindowSizeTransaction() {
+ // If we use BLASTSync we always consume the transaction when finishing
+ // the sync.
+ if (mService.useBLASTSync()) {
+ return false;
+ }
// We only consume the transaction when the client is calling relayout
// because this is the only time we know the frameNumber will be valid
// due to the client renderer being paused. Put otherwise, only when
@@ -988,7 +988,7 @@
if (!mPendingDestroySurface.mChildrenDetached) {
mPostDrawTransaction.reparentChildren(
mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl);
+ mSurfaceController.getClientViewRootSurface());
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8f1fb12..282cee0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2129,7 +2129,9 @@
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle, boolean parent) {
ensureLocked();
if (parent) {
- enforceManagedProfile(userHandle, "call APIs on the parent profile");
+ Preconditions.checkCallAuthorization(isManagedProfile(userHandle), String.format(
+ "You can not call APIs on the parent profile outside a managed profile, "
+ + "userId = %d", userHandle));
}
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
if (admin != null && parent) {
@@ -2266,10 +2268,6 @@
throw new SecurityException("Admin " + admin.info.getComponent()
+ " does not own the profile");
}
- if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
- throw new SecurityException("Admin " + admin.info.getComponent()
- + " is not the profile owner on organization-owned device");
- }
if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " is not a device owner or profile owner, so may not use policy: "
@@ -2284,8 +2282,8 @@
}
}
- ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent)
- throws SecurityException {
+ ActiveAdmin getActiveAdminForCallerLocked(@Nullable ComponentName who, int reqPolicy,
+ boolean parent) throws SecurityException {
return getActiveAdminOrCheckPermissionForCallerLocked(
who, reqPolicy, parent, /* permission= */ null);
}
@@ -2299,14 +2297,13 @@
*/
@Nullable
ActiveAdmin getActiveAdminOrCheckPermissionForCallerLocked(
- ComponentName who,
+ @Nullable ComponentName who,
int reqPolicy,
boolean parent,
@Nullable String permission) throws SecurityException {
ensureLocked();
if (parent) {
- enforceManagedProfile(mInjector.userHandleGetCallingUserId(),
- "call APIs on the parent profile");
+ Preconditions.checkCallingUser(isManagedProfile(getCallerIdentity().getUserId()));
}
ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
who, reqPolicy, permission);
@@ -2381,8 +2378,6 @@
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
return ownsDevice;
- } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
- return ownsDevice || ownsProfileOnOrganizationOwnedDevice;
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
// DO always has the PO power.
return ownsDevice || ownsProfileOnOrganizationOwnedDevice || ownsProfile;
@@ -2900,7 +2895,7 @@
if (!mHasFeature) {
return;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
synchronized (getLockObject()) {
final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
@@ -4096,10 +4091,13 @@
if (!mHasFeature) {
return true;
}
- final int userId = mInjector.userHandleGetCallingUserId();
- enforceProfileOrDeviceOwner(admin);
- enforceManagedProfile(userId, "query unified challenge status");
- return !isSeparateProfileChallengeEnabled(userId);
+ Objects.requireNonNull(admin, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+ Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
+
+ return !isSeparateProfileChallengeEnabled(caller.getUserId());
}
@Override
@@ -4111,7 +4109,9 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
- enforceManagedProfile(userHandle, "call APIs refering to the parent profile");
+ Preconditions.checkCallAuthorization(isManagedProfile(userHandle), String.format(
+ "can not call APIs refering to the parent profile outside a managed profile, "
+ + "userId = %d", userHandle));
synchronized (getLockObject()) {
final int targetUser = getProfileParentId(userHandle);
@@ -4133,7 +4133,9 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
- enforceNotManagedProfile(userHandle, "check password sufficiency");
+ Preconditions.checkCallAuthorization(!isManagedProfile(userHandle), String.format(
+ "You can not check password sufficiency for a managed profile, userId = %d",
+ userHandle));
enforceUserUnlocked(userHandle);
synchronized (getLockObject()) {
@@ -4689,8 +4691,9 @@
if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
return;
}
+ final CallerIdentity caller = getCallerIdentity();
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final int callingUserId = caller.getUserId();
ComponentName adminComponent = null;
synchronized (getLockObject()) {
// Make sure the caller has any active admin with the right policy or
@@ -4707,16 +4710,13 @@
// For Profile Owners only, callers with only permission not allowed.
if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
// Evict key
- enforceManagedProfile(
- callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+ Preconditions.checkCallingUser(isManagedProfile(callingUserId));
+ Preconditions.checkArgument(!parent,
+ "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
if (!isProfileOwner(adminComponent, callingUserId)) {
throw new SecurityException("Only profile owner admins can set "
+ "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
}
- if (parent) {
- throw new IllegalArgumentException(
- "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
- }
if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
throw new UnsupportedOperationException(
"FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
@@ -4761,32 +4761,20 @@
@Override
public void enforceCanManageCaCerts(ComponentName who, String callerPackage) {
- if (who == null) {
- if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
- DELEGATION_CERT_INSTALL)) {
- mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
- }
- } else {
- enforceProfileOrDeviceOwner(who);
- }
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(canManageCaCerts(caller));
}
- private void enforceProfileOrDeviceOwner(ComponentName who) {
- synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- }
- }
-
- private void enforceNetworkStackOrProfileOrDeviceOwner(ComponentName who) {
- if (hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)) {
- return;
- }
- enforceProfileOrDeviceOwner(who);
+ private boolean canManageCaCerts(CallerIdentity caller) {
+ return (caller.hasAdminComponent() && (isDeviceOwner(caller) || isProfileOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL))
+ || hasCallingOrSelfPermission(MANAGE_CA_CERTIFICATES);
}
@Override
public boolean approveCaCert(String alias, int userId, boolean approval) {
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
Set<String> certs = getUserData(userId).mAcceptedCaCertificates;
boolean changed = (approval ? certs.add(alias) : certs.remove(alias));
@@ -4801,7 +4789,8 @@
@Override
public boolean isCaCertApproved(String alias, int userId) {
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
return getUserData(userId).mAcceptedCaCertificates.contains(alias);
}
@@ -4826,21 +4815,20 @@
}
@Override
- public boolean installCaCert(ComponentName admin, String callerPackage, byte[] certBuffer)
- throws RemoteException {
+ public boolean installCaCert(ComponentName admin, String callerPackage, byte[] certBuffer) {
if (!mHasFeature) {
return false;
}
- enforceCanManageCaCerts(admin, callerPackage);
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ Preconditions.checkCallAuthorization(canManageCaCerts(caller));
- final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final String alias = mInjector.binderWithCleanCallingIdentity(() -> {
- String installedAlias = mCertificateMonitor.installCaCert(userHandle, certBuffer);
- final boolean isDelegate = (admin == null);
+ String installedAlias = mCertificateMonitor.installCaCert(
+ caller.getUserHandle(), certBuffer);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_CA_CERT)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ admin == null)
.write();
return installedAlias;
});
@@ -4851,8 +4839,8 @@
}
synchronized (getLockObject()) {
- getUserData(userHandle.getIdentifier()).mOwnerInstalledCaCerts.add(alias);
- saveSettingsLocked(userHandle.getIdentifier());
+ getUserData(caller.getUserId()).mOwnerInstalledCaCerts.add(alias);
+ saveSettingsLocked(caller.getUserId());
}
return true;
}
@@ -4862,22 +4850,22 @@
if (!mHasFeature) {
return;
}
- enforceCanManageCaCerts(admin, callerPackage);
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ Preconditions.checkCallAuthorization(canManageCaCerts(caller));
- final int userId = mInjector.userHandleGetCallingUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
- mCertificateMonitor.uninstallCaCerts(UserHandle.of(userId), aliases);
- final boolean isDelegate = (admin == null);
+ mCertificateMonitor.uninstallCaCerts(caller.getUserHandle(), aliases);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.UNINSTALL_CA_CERTS)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ admin == null)
.write();
});
synchronized (getLockObject()) {
- if (getUserData(userId).mOwnerInstalledCaCerts.removeAll(Arrays.asList(aliases))) {
- saveSettingsLocked(userId);
+ if (getUserData(caller.getUserId()).mOwnerInstalledCaCerts.removeAll(
+ Arrays.asList(aliases))) {
+ saveSettingsLocked(caller.getUserId());
}
}
}
@@ -5674,8 +5662,8 @@
throws SecurityException {
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOrDeviceOwner(who);
final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
final int userId = caller.getUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -5701,7 +5689,7 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setStrings(vpnPackage)
.setBoolean(lockdown)
.setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
@@ -5721,11 +5709,14 @@
@Override
public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException {
- enforceProfileOrDeviceOwner(admin);
+ Objects.requireNonNull(admin, "ComponentName is null");
- final int userId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
return mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId));
+ () -> mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(
+ caller.getUserId()));
}
@Override
@@ -5739,11 +5730,14 @@
@Override
public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
- enforceNetworkStackOrProfileOrDeviceOwner(admin);
+ Objects.requireNonNull(admin, "ComponentName is null");
- final int userId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK));
+
return mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(userId));
+ () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(caller.getUserId()));
}
@Override
@@ -5758,11 +5752,14 @@
@Override
public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
throws SecurityException {
- enforceProfileOrDeviceOwner(admin);
+ Objects.requireNonNull(admin, "ComponentName is null");
- final int userId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
return mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId));
+ () -> mInjector.getConnectivityManager().getVpnLockdownWhitelist(
+ caller.getUserId()));
}
private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
@@ -5945,14 +5942,15 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
final int frpManagementAgentUid = getFrpManagementAgentUidOrThrow();
- final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.mFactoryResetProtectionPolicy = policy;
- saveSettingsLocked(userId);
+ saveSettingsLocked(caller.getUserId());
}
final Intent intent = new Intent(
@@ -5977,21 +5975,23 @@
}
final int frpManagementAgentUid = getFrpManagementAgentUidOrThrow();
- ActiveAdmin admin;
+ final ActiveAdmin admin;
synchronized (getLockObject()) {
if (who == null) {
- if ((frpManagementAgentUid != mInjector.binderGetCallingUid())
- && !hasCallingPermission(permission.MASTER_CLEAR)) {
- throw new SecurityException(
- "Must be called by the FRP management agent on device");
- }
+ Preconditions.checkCallAuthorization(
+ frpManagementAgentUid == mInjector.binderGetCallingUid()
+ || hasCallingPermission(permission.MASTER_CLEAR),
+ "Must be called by the FRP management agent on device");
admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
UserHandle.getUserId(frpManagementAgentUid));
} else {
- admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller));
+ admin = getProfileOwnerOrDeviceOwnerLocked(caller);
}
}
+
return admin != null ? admin.mFactoryResetProtectionPolicy : null;
}
@@ -6049,11 +6049,13 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- enforceSystemCaller("report password change");
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(isSystemUid(caller));
// Managed Profile password can only be changed when it has a separate challenge.
if (!isSeparateProfileChallengeEnabled(userId)) {
- enforceNotManagedProfile(userId, "set the active password");
+ Preconditions.checkCallAuthorization(!isManagedProfile(userId), String.format("You can "
+ + "not set the active password for a managed profile, userId = %d", userId));
}
DevicePolicyData policy = getUserData(userId);
@@ -6106,8 +6108,9 @@
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (!isSeparateProfileChallengeEnabled(userHandle)) {
- enforceNotManagedProfile(userHandle,
- "report failed password attempt if separate profile challenge is not in place");
+ Preconditions.checkCallAuthorization(!isManagedProfile(userHandle), String.format(
+ "You can not report failed password attempt if separate profile challenge is "
+ + "not in place for a managed profile, userId = %d", userHandle));
}
boolean wipeData = false;
@@ -7332,7 +7335,7 @@
return null;
}
if (!callingUserOnly) {
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
}
synchronized (getLockObject()) {
if (!mOwners.hasDeviceOwner()) {
@@ -7351,7 +7354,8 @@
if (!mHasFeature) {
return UserHandle.USER_NULL;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
}
@@ -7366,7 +7370,8 @@
if (!mHasFeature) {
return null;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
if (!mOwners.hasDeviceOwner()) {
return null;
@@ -7591,8 +7596,10 @@
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userId = mInjector.userHandleGetCallingUserId();
- enforceNotManagedProfile(userId, "clear profile owner");
+ final CallerIdentity caller = getCallerIdentity(who);
+ final int userId = caller.getUserId();
+ Preconditions.checkCallingUser(!isManagedProfile(userId));
+
enforceUserUnlocked(userId);
synchronized (getLockObject()) {
// Check if this is the profile owner who is calling
@@ -7709,9 +7716,10 @@
if (!mHasFeature) {
return DevicePolicyManager.STATE_USER_UNMANAGED;
}
- enforceManageUsers();
- int userHandle = mInjector.userHandleGetCallingUserId();
- return getUserProvisioningState(userHandle);
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
+
+ return getUserProvisioningState(caller.getUserId());
}
private int getUserProvisioningState(int userHandle) {
@@ -7749,8 +7757,8 @@
}
transitionCheckNeeded = false;
} else {
- // For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS.
- enforceCanManageProfileAndDeviceOwners();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
}
final DevicePolicyData policyData = getUserData(userHandle);
@@ -7805,11 +7813,13 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ final int userId = caller.getUserId();
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallingUser(isManagedProfile(userId));
+
synchronized (getLockObject()) {
- // Check if this is the profile owner who is calling
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- final int userId = UserHandle.getCallingUserId();
- enforceManagedProfile(userId, "enable the profile");
// Check if the profile is already enabled.
UserInfo managedProfile = getUserInfo(userId);
if (managedProfile.isEnabled()) {
@@ -7835,14 +7845,15 @@
@Override
public void setProfileName(ComponentName who, String profileName) {
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOrDeviceOwner(who);
- final int userId = UserHandle.getCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
mInjector.binderWithCleanCallingIdentity(() -> {
- mUserManager.setUserName(userId, profileName);
+ mUserManager.setUserName(caller.getUserId(), profileName);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PROFILE_NAME)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.write();
});
}
@@ -7951,7 +7962,8 @@
if (!mHasFeature) {
return null;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
ComponentName profileOwner = getProfileOwner(userHandle);
if (profileOwner == null) {
return null;
@@ -8123,7 +8135,8 @@
}
return;
}
- enforceCanManageProfileAndDeviceOwners();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
if ((mIsWatch || hasUserSetupCompleted(userHandle))) {
if (!isCallerWithSystemUid()) {
@@ -8159,7 +8172,8 @@
@UserIdInt int userId,
boolean hasIncompatibleAccountsOrNonAdb) {
if (!isAdb()) {
- enforceCanManageProfileAndDeviceOwners();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
}
final int code = checkDeviceOwnerProvisioningPreConditionLocked(
@@ -8213,11 +8227,9 @@
}
}
- private void enforceManageUsers() {
- final int callingUid = mInjector.binderGetCallingUid();
- if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
- }
+ private boolean canManageUsers(CallerIdentity caller) {
+ return isSystemUid(caller) || isRootUid(caller)
+ || hasCallingOrSelfPermission(permission.MANAGE_USERS);
}
private boolean hasCallingPermission(String permission) {
@@ -8247,20 +8259,6 @@
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS);
}
- private void enforceManagedProfile(int userId, String message) {
- if (!isManagedProfile(userId)) {
- throw new SecurityException(String.format(
- "You can not %s outside a managed profile, userId = %d", message, userId));
- }
- }
-
- private void enforceNotManagedProfile(int userId, String message) {
- if (isManagedProfile(userId)) {
- throw new SecurityException(String.format(
- "You can not %s for a managed profile, userId = %d", message, userId));
- }
- }
-
private void enforceDeviceOwnerOrManageUsers() {
synchronized (getLockObject()) {
if (getActiveAdminWithPolicyForUidLocked(null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
@@ -8268,7 +8266,7 @@
return;
}
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
}
private void enforceProfileOwnerOrSystemUser() {
@@ -8882,7 +8880,8 @@
if (!mHasFeature) {
return null;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
List<String> result = null;
// If we have multiple profiles we return the intersection of the
@@ -8967,6 +8966,7 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
@@ -9008,6 +9008,7 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
@@ -9019,13 +9020,13 @@
@Override
public List getPermittedInputMethodsForCurrentUser() {
- enforceManageUsers();
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
- final int callingUserId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
List<String> result = null;
// Only device or profile owners can have permitted lists set.
- DevicePolicyData policy = getUserDataUnchecked(callingUserId);
+ DevicePolicyData policy = getUserDataUnchecked(caller.getUserId());
for (int i = 0; i < policy.mAdminList.size(); i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
List<String> fromAdmin = admin.permittedInputMethods;
@@ -9040,8 +9041,8 @@
// If we have a permitted list add all system input methods.
if (result != null) {
- List<InputMethodInfo> imes =
- InputMethodManagerInternal.get().getInputMethodListAsUser(callingUserId);
+ List<InputMethodInfo> imes = InputMethodManagerInternal
+ .get().getInputMethodListAsUser(caller.getUserId());
if (imes != null) {
for (InputMethodInfo ime : imes) {
ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -9485,11 +9486,12 @@
@Override
public boolean isEphemeralUser(ComponentName who) {
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOrDeviceOwner(who);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
return mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getUserManager().isUserEphemeral(callingUserId));
+ () -> mInjector.getUserManager().isUserEphemeral(caller.getUserId()));
}
@Override
@@ -9715,8 +9717,8 @@
boolean result;
synchronized (getLockObject()) {
if (parent) {
- getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(
+ caller.getUserId()) && isManagedProfile(caller.getUserId()));
// Ensure the package provided is a system package, this is to ensure that this
// API cannot be used to leak if certain non-system package exists in the person
// profile.
@@ -9747,8 +9749,9 @@
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
synchronized (getLockObject()) {
if (parent) {
- getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())
+ && isManagedProfile(caller.getUserId()));
// Ensure the package provided is a system package.
mInjector.binderWithCleanCallingIdentity(() ->
enforcePackageIsSystemPackage(packageName, userId));
@@ -10227,6 +10230,7 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
@@ -10250,6 +10254,7 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
@@ -10272,12 +10277,23 @@
@Override
public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled) {
- enforceCanSetSecondaryLockscreenEnabled(who);
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ // Check can set secondary lockscreen enabled
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+ Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
+ String.format("User %d is not allowed to call setSecondaryLockscreenEnabled",
+ caller.getUserId()));
+ // Allow testOnly admins to bypass supervision config requirement.
+ Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
+ || isDefaultSupervisor(caller), String.format("Admin %s is not the "
+ + "default supervision component", caller.getComponentName()));
+
synchronized (getLockObject()) {
- final int userId = mInjector.userHandleGetCallingUserId();
- DevicePolicyData policy = getUserData(userId);
+ DevicePolicyData policy = getUserData(caller.getUserId());
policy.mSecondaryLockscreenEnabled = enabled;
- saveSettingsLocked(userId);
+ saveSettingsLocked(caller.getUserId());
}
}
@@ -10288,31 +10304,14 @@
}
}
- private void enforceCanSetSecondaryLockscreenEnabled(ComponentName who) {
- enforceProfileOrDeviceOwner(who);
- final int userId = mInjector.userHandleGetCallingUserId();
- if (isManagedProfile(userId)) {
- throw new SecurityException(
- "User " + userId + " is not allowed to call setSecondaryLockscreenEnabled");
- }
- synchronized (getLockObject()) {
- if (isAdminTestOnlyLocked(who, userId)) {
- // Allow testOnly admins to bypass supervision config requirement.
- return;
- }
- }
- // Only the default supervision app can use this API.
+ private boolean isDefaultSupervisor(CallerIdentity caller) {
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
if (supervisor == null) {
- throw new SecurityException("Unable to set secondary lockscreen setting, no "
- + "default supervision component defined");
+ return false;
}
final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
- if (!who.equals(supervisorComponent)) {
- throw new SecurityException(
- "Admin " + who + " is not the default supervision component");
- }
+ return caller.getComponentName().equals(supervisorComponent);
}
@Override
@@ -11457,9 +11456,12 @@
policy.validateAgainstPreviousFreezePeriod(record.first, record.second,
LocalDate.now());
}
+ final CallerIdentity caller = getCallerIdentity(who);
+
synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller)
+ || isDeviceOwner(caller));
+
if (policy == null) {
mOwners.clearSystemUpdatePolicy();
} else {
@@ -11654,7 +11656,9 @@
@Override
public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin) {
Objects.requireNonNull(admin, "ComponentName is null");
- enforceProfileOrDeviceOwner(admin);
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
return mOwners.getSystemUpdateInfo();
}
@@ -11847,8 +11851,11 @@
@Override
public int checkProvisioningPreCondition(String action, String packageName) {
- Objects.requireNonNull(packageName);
- enforceCanManageProfileAndDeviceOwners();
+ Objects.requireNonNull(packageName, "packageName is null");
+
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
return checkProvisioningPreConditionSkipPermission(action, packageName);
}
@@ -12109,8 +12116,12 @@
@Override
public boolean isManagedProfile(ComponentName admin) {
- enforceProfileOrDeviceOwner(admin);
- return isManagedProfile(mInjector.userHandleGetCallingUserId());
+ Objects.requireNonNull(admin, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
+ return isManagedProfile(caller.getUserId());
}
@Override
@@ -12236,8 +12247,10 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
- enforceManagedProfile(caller.getUserId(), "set organization color");
+ Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.organizationColor = color;
@@ -12245,7 +12258,7 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ORGANIZATION_COLOR)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.write();
}
@@ -12258,9 +12271,10 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
+ Preconditions.checkCallAuthorization(isManagedProfile(userId), String.format("You can not "
+ + "set organization color outside a managed profile, userId = %d", userId));
- enforceManageUsers();
- enforceManagedProfile(userId, "set organization color");
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
admin.organizationColor = color;
@@ -12274,8 +12288,10 @@
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
- enforceManagedProfile(caller.getUserId(), "get organization color");
+ Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.organizationColor;
@@ -12291,8 +12307,9 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ Preconditions.checkCallAuthorization(isManagedProfile(userHandle), String.format("You can "
+ + "not get organization color outside a managed profile, userId = %d", userHandle));
- enforceManagedProfile(userHandle, "get organization color");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -12325,8 +12342,10 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
- enforceManagedProfile(caller.getUserId(), "get organization name");
+ Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.organizationName;
@@ -12354,8 +12373,10 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ Preconditions.checkCallAuthorization(isManagedProfile(userHandle), String.format(
+ "You can not get organization name outside a managed profile, userId = %d",
+ userHandle));
- enforceManagedProfile(userHandle, "get organization name");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -12667,10 +12688,11 @@
return;
}
Objects.requireNonNull(admin);
+ final CallerIdentity caller = getCallerIdentity(admin);
synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller)
+ || isDeviceOwner(caller));
if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
return;
}
@@ -12698,8 +12720,9 @@
synchronized (getLockObject()) {
if (!isCallerWithSystemUid()) {
Objects.requireNonNull(admin);
- getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
}
return mInjector.securityLogGetLoggingEnabledProperty();
}
@@ -12790,16 +12813,6 @@
return mSecurityLogMonitor.forceLogs();
}
- private void enforceCanManageDeviceAdmin() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
- null);
- }
-
- private void enforceCanManageProfileAndDeviceOwners() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
- }
-
private void enforceCallerSystemUserHandle() {
final int callingUid = mInjector.binderGetCallingUid();
final int userId = UserHandle.getUserId(callingUid);
@@ -12810,9 +12823,11 @@
@Override
public boolean isUninstallInQueue(final String packageName) {
- enforceCanManageDeviceAdmin();
- final int userId = mInjector.userHandleGetCallingUserId();
- Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+
+ Pair<String, Integer> packageUserPair = new Pair<>(packageName, caller.getUserId());
synchronized (getLockObject()) {
return mPackagesToRemove.contains(packageUserPair);
}
@@ -12820,11 +12835,13 @@
@Override
public void uninstallPackageWithActiveAdmins(final String packageName) {
- enforceCanManageDeviceAdmin();
Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
- final int userId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+ final int userId = caller.getUserId();
enforceUserUnlocked(userId);
final ComponentName profileOwner = getProfileOwner(userId);
@@ -12873,7 +12890,9 @@
@Override
public boolean isDeviceProvisioned() {
- enforceManageUsers();
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
+
synchronized (getLockObject()) {
return getUserDataUnchecked(UserHandle.USER_SYSTEM).mUserSetupComplete;
}
@@ -12957,7 +12976,8 @@
@Override
public void setDeviceProvisioningConfigApplied() {
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
policy.mDeviceProvisioningConfigApplied = true;
@@ -12967,7 +12987,8 @@
@Override
public boolean isDeviceProvisioningConfigApplied() {
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
synchronized (getLockObject()) {
final DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
return policy.mDeviceProvisioningConfigApplied;
@@ -12983,8 +13004,10 @@
*/
@Override
public void forceUpdateUserSetupComplete() {
- enforceCanManageProfileAndDeviceOwners();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
enforceCallerSystemUserHandle();
+
// no effect if it's called from user build
if (!mInjector.isBuildDebuggable()) {
return;
@@ -13005,25 +13028,28 @@
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(admin);
- enforceProfileOrDeviceOwner(admin);
- int userId = mInjector.userHandleGetCallingUserId();
- toggleBackupServiceActive(userId, enabled);
+ Objects.requireNonNull(admin, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
+ toggleBackupServiceActive(caller.getUserId(), enabled);
}
@Override
public boolean isBackupServiceEnabled(ComponentName admin) {
- Objects.requireNonNull(admin);
if (!mHasFeature) {
return true;
}
+ Objects.requireNonNull(admin, "ComponentName is null");
- enforceProfileOrDeviceOwner(admin);
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
synchronized (getLockObject()) {
try {
IBackupManager ibm = mInjector.getIBackupManager();
- return ibm != null && ibm.isBackupServiceActive(
- mInjector.userHandleGetCallingUserId());
+ return ibm != null && ibm.isBackupServiceActive(caller.getUserId());
} catch (RemoteException e) {
throw new IllegalStateException("Failed requesting backup service state.", e);
}
@@ -13605,13 +13631,14 @@
Objects.requireNonNull(admin, "ComponentName is null");
Objects.requireNonNull(packageName, "packageName is null");
Objects.requireNonNull(callback, "callback is null");
- enforceProfileOrDeviceOwner(admin);
- final int userId = UserHandle.getCallingUserId();
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
long ident = mInjector.binderClearCallingIdentity();
try {
ActivityManager.getService().clearApplicationUserData(packageName, false, callback,
- userId);
+ caller.getUserId());
} catch(RemoteException re) {
// Same process, should not happen.
} catch (SecurityException se) {
@@ -13664,7 +13691,9 @@
@Override
public List<String> getDisallowedSystemApps(ComponentName admin, int userId,
String provisioningAction) throws RemoteException {
- enforceCanManageProfileAndDeviceOwners();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
return new ArrayList<>(
mOverlayPackagesProvider.getNonRequiredApps(admin, userId, provisioningAction));
}
@@ -13675,31 +13704,23 @@
if (!mHasFeature) {
return;
}
-
- Objects.requireNonNull(admin, "Admin cannot be null.");
+ Objects.requireNonNull(admin, "ComponentName is null");
Objects.requireNonNull(target, "Target cannot be null.");
+ Preconditions.checkArgument(!admin.equals(target),
+ "Provided administrator and target are the same object.");
+ Preconditions.checkArgument(!admin.getPackageName().equals(target.getPackageName()),
+ "Provided administrator and target have the same package name.");
- enforceProfileOrDeviceOwner(admin);
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
- if (admin.equals(target)) {
- throw new IllegalArgumentException("Provided administrator and target are "
- + "the same object.");
- }
-
- if (admin.getPackageName().equals(target.getPackageName())) {
- throw new IllegalArgumentException("Provided administrator and target have "
- + "the same package name.");
- }
-
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final int callingUserId = caller.getUserId();
final DevicePolicyData policy = getUserData(callingUserId);
final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId,
/* throwForMissingPermission= */ true);
checkActiveAdminPrecondition(target, incomingDeviceInfo, policy);
- if (!incomingDeviceInfo.supportsTransferOwnership()) {
- throw new IllegalArgumentException("Provided target does not support "
- + "ownership transfer.");
- }
+ Preconditions.checkArgument(incomingDeviceInfo.supportsTransferOwnership(),
+ "Provided target does not support ownership transfer.");
final long id = mInjector.binderClearCallingIdentity();
String ownerType = null;
@@ -13722,7 +13743,7 @@
if (bundle == null) {
bundle = new PersistableBundle();
}
- if (isProfileOwner(admin, callingUserId)) {
+ if (isProfileOwner(caller)) {
ownerType = ADMIN_TYPE_PROFILE_OWNER;
prepareTransfer(admin, target, bundle, callingUserId,
ADMIN_TYPE_PROFILE_OWNER);
@@ -13733,7 +13754,7 @@
if (isUserAffiliatedWithDeviceLocked(callingUserId)) {
notifyAffiliatedProfileTransferOwnershipComplete(callingUserId);
}
- } else if (isDeviceOwner(admin, callingUserId)) {
+ } else if (isDeviceOwner(caller)) {
ownerType = ADMIN_TYPE_DEVICE_OWNER;
prepareTransfer(admin, target, bundle, callingUserId,
ADMIN_TYPE_DEVICE_OWNER);
@@ -14403,7 +14424,8 @@
if (!mHasFeature) {
return false;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
long id = mInjector.binderClearCallingIdentity();
try {
return isManagedKioskInternal();
@@ -14428,7 +14450,8 @@
if (!mHasFeature) {
return false;
}
- enforceManageUsers();
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
return mInjector.binderWithCleanCallingIdentity(() -> isUnattendedManagedKioskUnchecked());
}
@@ -14576,12 +14599,16 @@
@Override
public void setCommonCriteriaModeEnabled(ComponentName who, boolean enabled) {
- final int userId = mInjector.userHandleGetCallingUserId();
+ Objects.requireNonNull(who, "Admin component name must be provided");
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
+ "Common Criteria mode can only be controlled by a device owner or "
+ + "a profile owner on an organization-owned device.");
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.mCommonCriteriaMode = enabled;
- saveSettingsLocked(userId);
+ saveSettingsLocked(caller.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_COMMON_CRITERIA_MODE)
@@ -14593,9 +14620,14 @@
@Override
public boolean isCommonCriteriaModeEnabled(ComponentName who) {
if (who != null) {
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
+ "Common Criteria mode can only be controlled by a device owner or "
+ + "a profile owner on an organization-owned device.");
+
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.mCommonCriteriaMode;
}
}
@@ -14618,9 +14650,7 @@
Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
- false /* parent */);
+ final ActiveAdmin admin = getProfileOwnerOfCallerLocked(caller);
final long deadline = admin.mProfileOffDeadline;
final int result = makeSuspensionReasons(admin.mSuspendPersonalApps,
deadline != 0 && mInjector.systemCurrentTimeMillis() > deadline);
@@ -14653,9 +14683,7 @@
final int callingUserId = caller.getUserId();
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
- false /* parent */);
+ final ActiveAdmin admin = getProfileOwnerOfCallerLocked(caller);
boolean shouldSaveSettings = false;
if (admin.mSuspendPersonalApps != suspended) {
admin.mSuspendPersonalApps = suspended;
@@ -14916,9 +14944,7 @@
final int userId = caller.getUserId();
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
- false /* parent */);
+ final ActiveAdmin admin = getProfileOwnerOfCallerLocked(caller);
// Ensure the timeout is long enough to avoid having bad user experience.
if (timeoutMillis > 0 && timeoutMillis < MANAGED_PROFILE_MAXIMUM_TIME_OFF_THRESHOLD
@@ -14963,9 +14989,7 @@
Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
- false /* parent */);
+ final ActiveAdmin admin = getProfileOwnerOfCallerLocked(caller);
return admin.mProfileMaximumTimeOffMillis;
}
}
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 8b1e9c5..91cb481 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -30,6 +30,7 @@
import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -73,7 +74,7 @@
@Override
public void onStart() {
- publishBinderService(Context.PEOPLE_SERVICE, new BinderService());
+ publishBinderService(Context.PEOPLE_SERVICE, mService);
publishLocalService(PeopleServiceInternal.class, new LocalService());
}
@@ -117,7 +118,7 @@
message);
}
- private final class BinderService extends IPeopleManager.Stub {
+ final IBinder mService = new IPeopleManager.Stub() {
@Override
public ParceledListSlice<ConversationChannel> getRecentConversations() {
@@ -146,7 +147,7 @@
enforceSystemRootOrSystemUI(getContext(), "get last interaction");
return mDataManager.getLastInteraction(packageName, userId, shortcutId);
}
- }
+ };
@VisibleForTesting
final class LocalService extends PeopleServiceInternal {
diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
deleted file mode 100644
index 2d0fe58..0000000
--- a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
+++ /dev/null
@@ -1,76 +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 com.android.server.location;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.internal.util.IndentingPrintWriter;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-/**
- * Unit tests for {@link LocationRequestStatistics}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class LocationRequestStatisticsTest {
- private static final String FEATURE_ID = "featureId";
-
- /**
- * Check adding and removing requests & strings
- */
- @Test
- public void testRequestSummary() {
- LocationRequestStatistics.RequestSummary summary =
- new LocationRequestStatistics.RequestSummary(
- "com.example", FEATURE_ID, "gps", 1000);
- StringWriter stringWriter = new StringWriter();
- summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234);
- assertThat(stringWriter.toString()).startsWith("At");
-
- StringWriter stringWriterRemove = new StringWriter();
- summary = new LocationRequestStatistics.RequestSummary(
- "com.example", "gps", FEATURE_ID,
- LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
- summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345);
- assertThat(stringWriterRemove.toString()).contains("-");
- assertThat(stringWriterRemove.toString()).contains(FEATURE_ID);
- }
-
- /**
- * Check summary list size capping
- */
- @Test
- public void testSummaryList() {
- LocationRequestStatistics statistics = new LocationRequestStatistics();
- statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000);
- assertThat(statistics.history.mList.size()).isEqualTo(1);
- // Try (not) to overflow
- for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
- statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000);
- }
- assertThat(statistics.history.mList.size()).isEqualTo(
- LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
- }
-}
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index a398961..182fe9a 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.mockingservicestests">
- <uses-sdk android:targetSdkVersion="30" />
+ <uses-sdk android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index b4e8825..be258dc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -16,8 +16,6 @@
package com.android.server.location;
-import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
-import static android.app.AlarmManager.WINDOW_EXACT;
import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
@@ -41,7 +39,6 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.after;
@@ -55,8 +52,6 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.MockitoAnnotations.initMocks;
-import android.app.AlarmManager;
-import android.app.AlarmManager.OnAlarmListener;
import android.content.Context;
import android.location.ILocationCallback;
import android.location.ILocationListener;
@@ -66,14 +61,11 @@
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
-import android.os.Handler;
import android.os.ICancellationSignal;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.WorkSource;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
@@ -127,8 +119,6 @@
@Mock
private Context mContext;
@Mock
- private AlarmManager mAlarmManager;
- @Mock
private PowerManager mPowerManager;
@Mock
private PowerManager.WakeLock mWakeLock;
@@ -151,7 +141,6 @@
LocalServices.addService(LocationManagerInternal.class, mInternal);
doReturn("android").when(mContext).getPackageName();
- doReturn(mAlarmManager).when(mContext).getSystemService(AlarmManager.class);
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
@@ -505,19 +494,8 @@
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(5000).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
- long baseTimeMs = SystemClock.elapsedRealtime();
- ArgumentCaptor<Long> timeoutCapture = ArgumentCaptor.forClass(Long.class);
- ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
- OnAlarmListener.class);
- verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), timeoutCapture.capture(),
- eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
- any(WorkSource.class));
-
- assertThat(timeoutCapture.getValue()).isAtLeast(baseTimeMs + 4000);
- assertThat(timeoutCapture.getValue()).isAtMost(baseTimeMs + 5000);
- listenerCapture.getValue().onAlarm();
-
+ mInjector.getAlarmHelper().incrementAlarmTime(5000);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
verify(listener, never()).onLocationChanged(any(Location.class),
nullable(IRemoteCallback.class));
@@ -684,13 +662,7 @@
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
- ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
- OnAlarmListener.class);
- verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), anyLong(),
- eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
- any(WorkSource.class));
- listenerCapture.getValue().onAlarm();
-
+ mInjector.getAlarmHelper().incrementAlarmTime(60000);
verify(listener, times(1)).onLocation(isNull());
}
@@ -769,6 +741,40 @@
}
@Test
+ public void testProviderRequest_DelayedRequest() throws Exception {
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(60000).build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ verify(listener1).onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+
+ mInjector.getAlarmHelper().incrementAlarmTime(60000);
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(60000);
+ }
+
+ @Test
+ public void testProviderRequest_SpamRequesting() {
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(60000).build();
+
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+ mManager.unregisterLocationRequest(listener1);
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+ mManager.unregisterLocationRequest(listener1);
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+ }
+
+ @Test
public void testProviderRequest_BackgroundThrottle() {
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).build();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/FakeAlarmHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/util/FakeAlarmHelper.java
new file mode 100644
index 0000000..0e3e6ef
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/FakeAlarmHelper.java
@@ -0,0 +1,61 @@
+/*
+ * 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.location.util;
+
+import android.app.AlarmManager.OnAlarmListener;
+import android.os.WorkSource;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class FakeAlarmHelper extends AlarmHelper {
+
+ private static class Alarm {
+ public long delayMs;
+ public final OnAlarmListener listener;
+
+ Alarm(long delayMs, OnAlarmListener listener) {
+ this.delayMs = delayMs;
+ this.listener = listener;
+ }
+ }
+
+ private final ArrayList<Alarm> mAlarms = new ArrayList<>();
+
+ @Override
+ public void setDelayedAlarmInternal(long delayMs, OnAlarmListener listener,
+ WorkSource workSource) {
+ mAlarms.add(new Alarm(delayMs, listener));
+ }
+
+ @Override
+ public void cancel(OnAlarmListener listener) {
+ mAlarms.removeIf(alarm -> alarm.listener == listener);
+ }
+
+ public void incrementAlarmTime(long incrementMs) {
+ Iterator<Alarm> it = mAlarms.iterator();
+ while (it.hasNext()) {
+ Alarm alarm = it.next();
+ alarm.delayMs -= incrementMs;
+ if (alarm.delayMs <= 0) {
+ it.remove();
+ alarm.listener.onAlarm();
+ }
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/FakeLocationPowerSaveModeHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/util/FakeLocationPowerSaveModeHelper.java
index 3ead5d4..aea0170 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/util/FakeLocationPowerSaveModeHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/FakeLocationPowerSaveModeHelper.java
@@ -28,7 +28,8 @@
@LocationPowerSaveMode
private int mLocationPowerSaveMode;
- public FakeLocationPowerSaveModeHelper() {
+ public FakeLocationPowerSaveModeHelper(LocationEventLog locationEventLog) {
+ super(locationEventLog);
mLocationPowerSaveMode = IPowerManager.LOCATION_MODE_NO_CHANGE;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemLocationPowerSaveModeHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemLocationPowerSaveModeHelperTest.java
index 2acb70c..7890454 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemLocationPowerSaveModeHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemLocationPowerSaveModeHelperTest.java
@@ -84,7 +84,7 @@
Context context = mock(Context.class);
doReturn(powerManager).when(context).getSystemService(PowerManager.class);
- mHelper = new SystemLocationPowerSaveModeHelper(context);
+ mHelper = new SystemLocationPowerSaveModeHelper(context, new LocationEventLog());
mHelper.onSystemReady();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/util/TestInjector.java
index 1867be0..94651e6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/util/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/TestInjector.java
@@ -16,11 +16,11 @@
package com.android.server.location.util;
-import com.android.server.location.LocationRequestStatistics;
-
public class TestInjector implements Injector {
+ private final LocationEventLog mLocationEventLog;
private final FakeUserInfoHelper mUserInfoHelper;
+ private final FakeAlarmHelper mAlarmHelper;
private final FakeAppOpsHelper mAppOpsHelper;
private final FakeLocationPermissionsHelper mLocationPermissionsHelper;
private final FakeSettingsHelper mSettingsHelper;
@@ -29,19 +29,19 @@
private final FakeScreenInteractiveHelper mScreenInteractiveHelper;
private final LocationAttributionHelper mLocationAttributionHelper;
private final LocationUsageLogger mLocationUsageLogger;
- private final LocationRequestStatistics mLocationRequestStatistics;
public TestInjector() {
+ mLocationEventLog = new LocationEventLog();
mUserInfoHelper = new FakeUserInfoHelper();
+ mAlarmHelper = new FakeAlarmHelper();
mAppOpsHelper = new FakeAppOpsHelper();
mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
mSettingsHelper = new FakeSettingsHelper();
mAppForegroundHelper = new FakeAppForegroundHelper();
- mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper();
+ mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(mLocationEventLog);
mScreenInteractiveHelper = new FakeScreenInteractiveHelper();
mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper);
mLocationUsageLogger = new LocationUsageLogger();
- mLocationRequestStatistics = new LocationRequestStatistics();
}
@Override
@@ -50,6 +50,11 @@
}
@Override
+ public FakeAlarmHelper getAlarmHelper() {
+ return mAlarmHelper;
+ }
+
+ @Override
public FakeAppOpsHelper getAppOpsHelper() {
return mAppOpsHelper;
}
@@ -90,7 +95,7 @@
}
@Override
- public LocationRequestStatistics getLocationRequestStatistics() {
- return mLocationRequestStatistics;
+ public LocationEventLog getLocationEventLog() {
+ return mLocationEventLog;
}
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 7fc6bbd7..1f72374 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -78,6 +78,7 @@
"libbinder",
"libc++",
"libcutils",
+ "libicing",
"liblog",
"liblzma",
"libnativehelper",
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java
new file mode 100644
index 0000000..24f7830
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java
@@ -0,0 +1,345 @@
+/*
+ * 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 com.android.server.appsearch.external.localbackend;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.android.server.appsearch.proto.DocumentProto;
+import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
+import com.android.server.appsearch.proto.IndexingConfig;
+import com.android.server.appsearch.proto.PropertyConfigProto;
+import com.android.server.appsearch.proto.PropertyProto;
+import com.android.server.appsearch.proto.ResultSpecProto;
+import com.android.server.appsearch.proto.SchemaProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
+import com.android.server.appsearch.proto.ScoringSpecProto;
+import com.android.server.appsearch.proto.SearchResultProto;
+import com.android.server.appsearch.proto.SearchSpecProto;
+import com.android.server.appsearch.proto.StatusProto;
+import com.android.server.appsearch.proto.TermMatchType;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.Set;
+
+public class AppSearchImplTest {
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchImpl mAppSearchImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ mAppSearchImpl = new AppSearchImpl(mTemporaryFolder.newFolder());
+ mAppSearchImpl.initialize();
+ }
+
+ /**
+ * Ensure that we can rewrite an incoming schema type by adding the database as a prefix. While
+ * also keeping any other existing schema types that may already be part of Icing's persisted
+ * schema.
+ */
+ @Test
+ public void testRewriteSchema() throws Exception {
+ SchemaProto.Builder existingSchemaBuilder = mAppSearchImpl.getSchemaProto().toBuilder();
+
+ SchemaProto newSchema = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("Foo").build())
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("TestType")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ IndexingConfig.newBuilder()
+ .setTokenizerType(
+ IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ .build()
+ ).build()
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("link")
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setSchemaType("RefType")
+ .build()
+ ).build()
+ ).build();
+
+ Set<String> newTypes = mAppSearchImpl.rewriteSchema("databaseName", existingSchemaBuilder,
+ newSchema);
+ assertThat(newTypes).containsExactly("databaseName/Foo", "databaseName/TestType");
+
+ SchemaProto expectedSchema = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("databaseName/Foo").build())
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("databaseName/TestType")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ IndexingConfig.newBuilder()
+ .setTokenizerType(
+ IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ .build()
+ ).build()
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("link")
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setSchemaType("databaseName/RefType")
+ .build()
+ ).build())
+ .build();
+ assertThat(existingSchemaBuilder.getTypesList())
+ .containsExactlyElementsIn(expectedSchema.getTypesList());
+ }
+
+ @Test
+ public void testRewriteDocumentProto() {
+ DocumentProto insideDocument = DocumentProto.newBuilder()
+ .setUri("inside-uri")
+ .setSchema("type")
+ .setNamespace("namespace")
+ .build();
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri("uri")
+ .setSchema("type")
+ .setNamespace("namespace")
+ .addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
+ .build();
+
+ DocumentProto expectedInsideDocument = DocumentProto.newBuilder()
+ .setUri("inside-uri")
+ .setSchema("databaseName/type")
+ .setNamespace("databaseName/namespace")
+ .build();
+ DocumentProto expectedDocumentProto = DocumentProto.newBuilder()
+ .setUri("uri")
+ .setSchema("databaseName/type")
+ .setNamespace("databaseName/namespace")
+ .addProperties(PropertyProto.newBuilder().addDocumentValues(expectedInsideDocument))
+ .build();
+
+ DocumentProto.Builder actualDocument = documentProto.toBuilder();
+ mAppSearchImpl.rewriteDocumentTypes("databaseName/", actualDocument, /*add=*/true);
+ assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
+ mAppSearchImpl.rewriteDocumentTypes("databaseName/", actualDocument, /*add=*/false);
+ assertThat(actualDocument.build()).isEqualTo(documentProto);
+ }
+
+ @Test
+ public void testOptimize() throws Exception {
+ // Insert schema
+ SchemaProto schema = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("type").build())
+ .build();
+ mAppSearchImpl.setSchema("database", schema, /*forceOverride=*/false);
+
+ // Insert enough documents.
+ for (int i = 0; i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT
+ + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL; i++) {
+ DocumentProto insideDocument = DocumentProto.newBuilder()
+ .setUri("inside-uri" + i)
+ .setSchema("type")
+ .setNamespace("namespace")
+ .build();
+ mAppSearchImpl.putDocument("database", insideDocument);
+ }
+
+ // Check optimize() will release 0 docs since there is no deletion.
+ GetOptimizeInfoResultProto optimizeInfo = mAppSearchImpl.getOptimizeInfoResult();
+ assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(0);
+
+ // delete 999 documents , we will reach the threshold to trigger optimize() in next
+ // deletion.
+ for (int i = 0; i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT - 1; i++) {
+ mAppSearchImpl.remove("database", "namespace", "inside-uri" + i);
+ }
+
+ // optimize() still not be triggered since we are in the interval to call getOptimizeInfo()
+ optimizeInfo = mAppSearchImpl.getOptimizeInfoResult();
+ assertThat(optimizeInfo.getOptimizableDocs())
+ .isEqualTo(AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT - 1);
+
+ // Keep delete docs, will reach the interval this time and trigger optimize().
+ for (int i = AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT;
+ i < AppSearchImpl.OPTIMIZE_THRESHOLD_DOC_COUNT
+ + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL; i++) {
+ mAppSearchImpl.remove("database", "namespace", "inside-uri" + i);
+ }
+
+ // Verify optimize() is triggered
+ optimizeInfo = mAppSearchImpl.getOptimizeInfoResult();
+ assertThat(optimizeInfo.getOptimizableDocs())
+ .isLessThan((long) AppSearchImpl.CHECK_OPTIMIZE_INTERVAL);
+ }
+
+ @Test
+ public void testRewriteSearchSpec() throws Exception {
+ SearchSpecProto.Builder searchSpecProto =
+ SearchSpecProto.newBuilder().setQuery("");
+
+ // Insert schema
+ SchemaProto schema = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("type").build())
+ .build();
+ mAppSearchImpl.setSchema("database", schema, /*forceOverride=*/false);
+ // Insert document
+ DocumentProto insideDocument = DocumentProto.newBuilder()
+ .setUri("inside-uri")
+ .setSchema("type")
+ .setNamespace("namespace")
+ .build();
+ mAppSearchImpl.putDocument("database", insideDocument);
+
+ // Rewrite SearchSpec
+ mAppSearchImpl.rewriteSearchSpecForNonEmptyDatabase(
+ "database", searchSpecProto);
+ assertThat(searchSpecProto.getSchemaTypeFiltersList()).containsExactly("database/type");
+ assertThat(searchSpecProto.getNamespaceFiltersList()).containsExactly("database/namespace");
+ }
+
+ @Test
+ public void testQueryEmptyDatabase() throws Exception {
+ SearchResultProto searchResultProto = mAppSearchImpl.query("EmptyDatabase",
+ SearchSpecProto.getDefaultInstance(),
+ ResultSpecProto.getDefaultInstance(), ScoringSpecProto.getDefaultInstance());
+ assertThat(searchResultProto.getResultsCount()).isEqualTo(0);
+ assertThat(searchResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ }
+
+ @Test
+ public void testRemoveEmptyDatabase_NoExceptionThrown() throws Exception {
+ mAppSearchImpl.removeByType("EmptyDatabase", "FakeType");
+ mAppSearchImpl.removeByNamespace("EmptyDatabase", "FakeNamespace");
+ mAppSearchImpl.removeAll("EmptyDatabase");
+ }
+
+ @Test
+ public void testSetSchema() throws Exception {
+ // Create schemas
+ SchemaProto schemaProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Email")).build();
+
+ // Set schema Email to AppSearch database1
+ mAppSearchImpl.setSchema("database1", schemaProto, /*forceOverride=*/false);
+
+ // Create excepted schemaType proto.
+ SchemaProto exceptedProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Email"))
+ .build();
+ assertThat(mAppSearchImpl.getSchemaProto().getTypesList())
+ .containsExactlyElementsIn(exceptedProto.getTypesList());
+ }
+
+ @Test
+ public void testRemoveSchema() throws Exception {
+ // Create schemas
+ SchemaProto schemaProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Document")).build();
+
+ // Set schema Email and Document to AppSearch database1
+ mAppSearchImpl.setSchema("database1", schemaProto, /*forceOverride=*/false);
+
+ // Create excepted schemaType proto.
+ SchemaProto exceptedProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Document"))
+ .build();
+
+ // Check both schema Email and Document saved correctly.
+ assertThat(mAppSearchImpl.getSchemaProto().getTypesList())
+ .containsExactlyElementsIn(exceptedProto.getTypesList());
+
+ // Save only Email this time.
+ schemaProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Email")).build();
+
+ // Check the incompatible error has been thrown.
+ SchemaProto finalSchemaProto = schemaProto;
+ AppSearchException e = expectThrows(AppSearchException.class, () ->
+ mAppSearchImpl.setSchema("database1", finalSchemaProto, /*forceOverride=*/false));
+ assertThat(e).hasMessageThat().isEqualTo("Schema is incompatible.");
+
+ // ForceOverride to delete.
+ mAppSearchImpl.setSchema("database1", finalSchemaProto, /*forceOverride=*/true);
+
+ // Check Document schema is removed.
+ exceptedProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Email"))
+ .build();
+ assertThat(mAppSearchImpl.getSchemaProto().getTypesList())
+ .containsExactlyElementsIn(exceptedProto.getTypesList());
+ }
+
+ @Test
+ public void testRemoveSchema_differentDataBase() throws Exception {
+ // Create schemas
+ SchemaProto emailAndDocSchemaProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Document")).build();
+
+ // Set schema Email and Document to AppSearch database1 and 2
+ mAppSearchImpl.setSchema("database1", emailAndDocSchemaProto, /*forceOverride=*/false);
+ mAppSearchImpl.setSchema("database2", emailAndDocSchemaProto, /*forceOverride=*/false);
+
+ // Create excepted schemaType proto.
+ SchemaProto exceptedProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Document"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database2/Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database2/Document"))
+ .build();
+
+ // Check Email and Document is saved in database 1 and 2 correctly.
+ assertThat(mAppSearchImpl.getSchemaProto().getTypesList())
+ .containsExactlyElementsIn(exceptedProto.getTypesList());
+
+ // Save only Email to database1 this time.
+ SchemaProto emailSchemaProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Email"))
+ .build();
+ mAppSearchImpl.setSchema("database1", emailSchemaProto, /*forceOverride=*/true);
+
+ // Create excepted schemaType list, database 1 should only contain Email but database 2
+ // remains in same.
+ exceptedProto = SchemaProto.newBuilder()
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database1/Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database2/Email"))
+ .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("database2/Document"))
+ .build();
+
+ // Check nothing changed in database2.
+ assertThat(mAppSearchImpl.getSchemaProto().getTypesList())
+ .containsExactlyElementsIn(exceptedProto.getTypesList());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
deleted file mode 100644
index 8986cba..0000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.expectThrows;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.os.UserHandle;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.appsearch.proto.IndexingConfig;
-import com.android.server.appsearch.proto.PropertyConfigProto;
-import com.android.server.appsearch.proto.SchemaProto;
-import com.android.server.appsearch.proto.SchemaTypeConfigProto;
-import com.android.server.appsearch.proto.TermMatchType;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class AppSearchImplTest {
- private final Context mContext = InstrumentationRegistry.getContext();
- private final @UserIdInt int mUserId = UserHandle.getCallingUserId();
-
- @Test
- public void testRewriteSchemaTypes() {
- SchemaProto inSchema = SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("TestType")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- IndexingConfig.newBuilder()
- .setTokenizerType(
- IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- .build()
- ).build()
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setSchemaType("RefType")
- .build()
- ).build()
- ).build();
-
- SchemaProto expectedSchema = SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("com.android.server.appsearch.impl@42:TestType")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- IndexingConfig.newBuilder()
- .setTokenizerType(
- IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- .build()
- ).build()
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setSchemaType("com.android.server.appsearch.impl@42:RefType")
- .build()
- ).build()
- ).build();
-
- AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
- SchemaProto.Builder actualSchema = inSchema.toBuilder();
- impl.rewriteSchemaTypes("com.android.server.appsearch.impl@42:", actualSchema);
-
- assertThat(actualSchema.build()).isEqualTo(expectedSchema);
- }
-
- @Test
- public void testPackageNotFound() {
- AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
- IllegalStateException e = expectThrows(
- IllegalStateException.class,
- () -> impl.setSchema(
- /*callingUid=*/Integer.MAX_VALUE,
- SchemaProto.getDefaultInstance(),
- /*forceOverride=*/false));
- assertThat(e).hasMessageThat().contains("Failed to look up package name");
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
deleted file mode 100644
index 3196fbe..0000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.appsearch.proto.DocumentProto;
-import com.android.server.appsearch.proto.PropertyProto;
-import com.android.server.appsearch.proto.SearchResultProto;
-import com.android.server.appsearch.proto.StatusProto;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-public class FakeIcingTest {
- @Test
- public void query() {
- FakeIcing icing = new FakeIcing();
- icing.put(createDoc("uri:cat", "The cat said meow"));
- icing.put(createDoc("uri:dog", "The dog said woof"));
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "fred")).isEmpty();
- }
-
- @Test
- public void queryNorm() {
- FakeIcing icing = new FakeIcing();
- icing.put(createDoc("uri:cat", "The cat said meow"));
- icing.put(createDoc("uri:dog", "The dog said woof"));
-
- assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
- }
-
- @Test
- public void get() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
- }
-
- @Test
- public void replace() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- icing.put(dog);
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
- // Replace
- DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
- DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
- icing.put(cat2);
- icing.put(bird);
-
- assertThat(queryGetUris(icing, "meow")).isEmpty();
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
- assertThat(icing.get("uri:cat")).isEqualTo(cat2);
- }
-
- @Test
- public void delete() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- icing.put(dog);
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
- // Delete
- icing.delete("uri:cat");
- icing.delete("uri:notreal");
-
- assertThat(queryGetUris(icing, "meow")).isEmpty();
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
- assertThat(icing.get("uri:cat")).isNull();
- }
-
- private static DocumentProto createDoc(String uri, String body) {
- return DocumentProto.newBuilder()
- .setUri(uri)
- .addProperties(PropertyProto.newBuilder().addStringValues(body))
- .build();
- }
-
- private static List<String> queryGetUris(FakeIcing icing, String term) {
- List<String> uris = new ArrayList<>();
- SearchResultProto results = icing.query(term);
- assertThat(results.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
- for (SearchResultProto.ResultProto result : results.getResultsList()) {
- uris.add(result.getDocument().getUri());
- }
- return uris;
- }
-}
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 36c55cc..c890c52 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
@@ -16,11 +16,21 @@
package com.android.server.biometrics.sensors;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+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 android.content.Context;
+import android.hardware.biometrics.IBiometricService;
import android.platform.test.annotations.Presubmit;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -40,18 +50,21 @@
@Mock
private Context mContext;
@Mock
- private ClientMonitor.LazyDaemon<Object> mLazyDaemon;
+ private IBiometricService mBiometricService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
+ mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */,
+ mBiometricService);
}
@Test
public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
- final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, mLazyDaemon);
- final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, mLazyDaemon);
+ final ClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
+
+ final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, nonNullDaemon);
+ final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, nonNullDaemon);
mScheduler.scheduleClientMonitor(client1);
mScheduler.scheduleClientMonitor(client2);
@@ -59,7 +72,93 @@
client1.mCallback.onClientFinished(client1, true /* success */);
}
+ @Test
+ public void testRemovesPendingOperations_whenNullHal_andNotBiometricPrompt() {
+ // Even if second client has a non-null daemon, it needs to be canceled.
+ Object daemon2 = mock(Object.class);
+
+ final ClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
+ final ClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
+
+ final TestClientMonitor client1 = new TestClientMonitor(mContext, lazyDaemon1);
+ final TestClientMonitor client2 = new TestClientMonitor(mContext, lazyDaemon2);
+
+ final ClientMonitor.Callback callback1 = mock(ClientMonitor.Callback.class);
+ final ClientMonitor.Callback callback2 = mock(ClientMonitor.Callback.class);
+
+ // Pretend the scheduler is busy so the first operation doesn't start right away. We want
+ // to pretend like there are two operations in the queue before kicking things off
+ mScheduler.mCurrentOperation = new BiometricScheduler.Operation(
+ mock(ClientMonitor.class), mock(ClientMonitor.Callback.class));
+
+ mScheduler.scheduleClientMonitor(client1, callback1);
+ assertEquals(1, mScheduler.mPendingOperations.size());
+ // client1 is pending. Allow the scheduler to start once second client is added.
+ mScheduler.mCurrentOperation = null;
+ mScheduler.scheduleClientMonitor(client2, callback2);
+ waitForIdle();
+
+ assertTrue(client1.wasUnableToStart());
+ verify(callback1).onClientFinished(eq(client1), eq(false) /* success */);
+ verify(callback1, never()).onClientStarted(any());
+
+ assertTrue(client2.wasUnableToStart());
+ verify(callback2).onClientFinished(eq(client2), eq(false) /* success */);
+ verify(callback2, never()).onClientStarted(any());
+
+ assertTrue(mScheduler.mPendingOperations.isEmpty());
+ }
+
+ @Test
+ public void testRemovesOnlyBiometricPromptOperation_whenNullHal() {
+ // Second non-BiometricPrompt client has a valid daemon
+ final Object daemon2 = mock(Object.class);
+
+ final ClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
+ final ClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
+
+ final TestClientMonitor client1 =
+ new TestBiometricPromptClientMonitor(mContext, lazyDaemon1);
+ final TestClientMonitor client2 = new TestClientMonitor(mContext, lazyDaemon2);
+
+ final ClientMonitor.Callback callback1 = mock(ClientMonitor.Callback.class);
+ final ClientMonitor.Callback callback2 = mock(ClientMonitor.Callback.class);
+
+ // Pretend the scheduler is busy so the first operation doesn't start right away. We want
+ // to pretend like there are two operations in the queue before kicking things off
+ mScheduler.mCurrentOperation = new BiometricScheduler.Operation(
+ mock(ClientMonitor.class), mock(ClientMonitor.Callback.class));
+
+ mScheduler.scheduleClientMonitor(client1, callback1);
+ assertEquals(1, mScheduler.mPendingOperations.size());
+ // client1 is pending. Allow the scheduler to start once second client is added.
+ mScheduler.mCurrentOperation = null;
+ mScheduler.scheduleClientMonitor(client2, callback2);
+ waitForIdle();
+
+ // Simulate that the BiometricPrompt client's sensor is ready
+ mScheduler.startPreparedClient(client1.getCookie());
+
+ assertTrue(client1.wasUnableToStart());
+ verify(callback1).onClientFinished(eq(client1), eq(false) /* success */);
+ verify(callback1, never()).onClientStarted(any());
+
+ // Client 2 was able to start
+ assertFalse(client2.wasUnableToStart());
+ assertTrue(client2.hasStarted());
+ verify(callback2).onClientStarted(eq(client2));
+ }
+
+ private static class TestBiometricPromptClientMonitor extends TestClientMonitor {
+ public TestBiometricPromptClientMonitor(@NonNull Context context,
+ @NonNull LazyDaemon<Object> lazyDaemon) {
+ super(context, lazyDaemon, 1 /* cookie */);
+ }
+ }
+
private static class TestClientMonitor extends ClientMonitor<Object> {
+ private boolean mUnableToStart;
+ private boolean mStarted;
public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon) {
super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
@@ -67,14 +166,42 @@
0 /* statsAction */, 0 /* statsClient */);
}
+ public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon,
+ int cookie) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
+ TAG, cookie, 0 /* sensorId */, 0 /* statsModality */,
+ 0 /* statsAction */, 0 /* statsClient */);
+ }
+
+
@Override
public void unableToStart() {
+ assertFalse(mUnableToStart);
+ mUnableToStart = true;
+ }
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+ assertFalse(mStarted);
+ mStarted = true;
}
@Override
protected void startHalOperation() {
}
+
+ public boolean wasUnableToStart() {
+ return mUnableToStart;
+ }
+
+ public boolean hasStarted() {
+ return mStarted;
+ }
+ }
+
+ private static void waitForIdle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java
new file mode 100644
index 0000000..7a0d894
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java
@@ -0,0 +1,69 @@
+/*
+ * 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.biometrics.sensors.face;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class Face10Test {
+
+ private static final String TAG = "Face10Test";
+ private static final int SENSOR_ID = 1;
+
+ @Mock
+ private Context mContext;
+
+ private LockoutResetDispatcher mLockoutResetDispatcher;
+ private Face10 mFace10;
+ private IBinder mBinder;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
+ mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG,
+ mLockoutResetDispatcher, false /* supportsSelfIllumination */,
+ 1 /* maxTemplatesAllowed */);
+ mBinder = new Binder();
+ }
+
+ @Test
+ public void scheduleRevokeChallenge_doesNotCrash() {
+ mFace10.scheduleRevokeChallenge(mBinder, TAG);
+ waitForIdle();
+ }
+
+ private static void waitForIdle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 4ce6411..631b4d4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4407,7 +4407,7 @@
// Caller is Profile Owner, but no supervision app is configured.
setAsProfileOwner(admin1);
- assertExpectException(SecurityException.class, "no default supervision component defined",
+ assertExpectException(SecurityException.class, "is not the default supervision component",
() -> dpm.setSecondaryLockscreenEnabled(admin1, true));
assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
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 63ad53b..2a9c394 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -160,7 +160,7 @@
assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
playbackDevice.mAddress);
assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
- assertThat(playbackDevice.mIsActiveSource).isTrue();
+ assertThat(playbackDevice.isActiveSource()).isTrue();
}
@Test
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 415ae07..74fd683 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -30,10 +30,15 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.media.AudioManager;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -47,6 +52,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -81,8 +88,17 @@
private HdmiPortInfo[] mHdmiPortInfo;
private boolean mWokenUp;
+ @Mock private IPowerManager mIPowerManagerMock;
+ @Mock private IThermalService mIThermalServiceMock;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ Context context = InstrumentationRegistry.getTargetContext();
+ mMyLooper = mTestLooper.getLooper();
+ PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
+ mIThermalServiceMock, new Handler(mMyLooper));
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -166,6 +182,11 @@
return defVal;
}
}
+
+ @Override
+ PowerManager getPowerManager() {
+ return powerManager;
+ }
};
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
@@ -174,11 +195,6 @@
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@Override
- void setIsActiveSource(boolean on) {
- mIsActiveSource = on;
- }
-
- @Override
protected int getPreferredAddress() {
return ADDR_PLAYBACK_1;
}
@@ -827,4 +843,68 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected);
}
+
+ @Test
+ public void setActiveSource_localDevice_playback() {
+ mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
+ SELF_PHYSICAL_ADDRESS,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mHdmiCecLocalDevicePlayback.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ SELF_PHYSICAL_ADDRESS);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_localDevice_audio() {
+ mHdmiControlService.setActiveSource(mHdmiCecLocalDeviceAudioSystem.mAddress,
+ SELF_PHYSICAL_ADDRESS,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mHdmiCecLocalDeviceAudioSystem.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ SELF_PHYSICAL_ADDRESS);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isTrue();
+ }
+
+ @Test
+ public void setActiveSource_remoteDevice() {
+ mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_TV);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_nonCecDevice() {
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_unknown() {
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ Constants.INVALID_PHYSICAL_ADDRESS);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.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 498ebf4..7cbf571 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -17,6 +17,7 @@
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_INVALID;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -266,106 +267,197 @@
@Test
public void handleRoutingChange_otherDevice_None() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ 0x5000);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleRoutingChange_sameDevice_None_ActiveSource() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+ mStandby = false;
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mPlaybackLogicalAddress);
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleRoutingChange_sameDevice_None_InactiveSource() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
+ mStandby = false;
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
assertThat(mStandby).isFalse();
}
@Test
public void handleRoutingChange_otherDevice_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isTrue();
}
@Test
public void handleRoutingChange_otherDevice_StandbyNow_InactiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isFalse();
}
@Test
public void handleRoutingChange_sameDevice_StandbyNow_ActiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
assertThat(mStandby).isFalse();
}
@Test
public void handleRoutingInformation_otherDevice_None() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+ mStandby = false;
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ 0x5000);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleRoutingInformation_sameDevice_None_ActiveSource() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
- HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+ mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mPlaybackLogicalAddress);
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleRoutingInformation_sameDevice_None_InactiveSource() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
+ mStandby = false;
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
assertThat(mStandby).isFalse();
}
@Test
public void handleRoutingInformation_otherDevice_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isTrue();
}
@Test
public void handleRoutingInformation_otherDevice_StandbyNow_InactiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isFalse();
}
@Test
public void handleRoutingInformation_sameDevice_StandbyNow_ActiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
assertThat(mStandby).isFalse();
}
@@ -430,7 +522,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -449,7 +542,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -468,7 +562,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -487,7 +582,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -506,7 +602,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -525,7 +622,8 @@
mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
@@ -549,6 +647,11 @@
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mPlaybackLogicalAddress);
}
@Test
@@ -560,6 +663,11 @@
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ 0x0000);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_TV);
}
@Test
@@ -572,6 +680,7 @@
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
}
@Test
@@ -583,6 +692,7 @@
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
}
@Test
@@ -703,7 +813,7 @@
mPlaybackLogicalAddress, ADDR_TV);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
}
@@ -723,7 +833,7 @@
mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
}
@@ -742,7 +852,7 @@
mPlaybackLogicalAddress, ADDR_TV);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
}
@@ -761,7 +871,7 @@
mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
}
@@ -805,21 +915,28 @@
mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
}
@Test
public void handleSetStreamPath_otherDevice_None() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ 0x5000);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
assertThat(mStandby).isFalse();
}
@@ -827,12 +944,13 @@
public void handleSetStreamPath_otherDevice_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isTrue();
}
@@ -840,12 +958,13 @@
public void handleSetStreamPath_otherDevice_StandbyNow_InactiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
- mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+ "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
- assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
assertThat(mStandby).isFalse();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
index 7560a34..c4068d3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
@@ -138,11 +138,6 @@
mPlaybackDevice = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@Override
- void setIsActiveSource(boolean on) {
- mIsActiveSource = on;
- }
-
- @Override
protected void wakeUpIfActiveSource() {}
@Override
@@ -186,13 +181,13 @@
}
});
assertEquals(mResult, -1);
- assertThat(mPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mPlaybackDevice.isActiveSource()).isFalse();
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
assertThat(mHdmiControlService.isAddressAllocated()).isTrue();
assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS);
- assertThat(mPlaybackDevice.mIsActiveSource).isTrue();
+ assertThat(mPlaybackDevice.isActiveSource()).isTrue();
}
@Test
@@ -207,6 +202,6 @@
}
});
assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS);
- assertThat(mPlaybackDevice.mIsActiveSource).isTrue();
+ assertThat(mPlaybackDevice.isActiveSource()).isTrue();
}
}
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 4849dd4..2f48b5e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -405,82 +405,6 @@
assertThat(callback2.mVolumeControlEnabled).isTrue();
}
- @Test
- public void setActiveSource_localDevice_playback() {
- int physicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(physicalAddress);
-
- mHdmiControlService.setActiveSource(mMyPlaybackDevice.mAddress, physicalAddress,
- "HdmiControlServiceTest");
-
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- mMyPlaybackDevice.mAddress);
- assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
- physicalAddress);
- assertThat(mMyPlaybackDevice.mIsActiveSource).isTrue();
- assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
- }
-
- @Test
- public void setActiveSource_localDevice_audio() {
- int physicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(physicalAddress);
-
- mHdmiControlService.setActiveSource(mMyAudioSystemDevice.mAddress, physicalAddress,
- "HdmiControlServiceTest");
-
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- mMyAudioSystemDevice.mAddress);
- assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
- physicalAddress);
- assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
- assertThat(mMyAudioSystemDevice.mIsActiveSource).isTrue();
- }
-
- @Test
- public void setActiveSource_remoteDevice() {
- int physicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(physicalAddress);
-
- mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
-
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- Constants.ADDR_TV);
- assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
- assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
- assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
- }
-
- @Test
- public void setActiveSource_nonCecDevice() {
- int physicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(physicalAddress);
-
- mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
- "HdmiControlServiceTest");
-
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- Constants.ADDR_INVALID);
- assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
- assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
- assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
- }
-
- @Test
- public void setActiveSource_unknown() {
- int physicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(physicalAddress);
-
- mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
- Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
-
- assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
- Constants.ADDR_INVALID);
- assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
- Constants.INVALID_PHYSICAL_ADDRESS);
- assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
- assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
- }
private static class VolumeControlFeatureCallback extends
IHdmiCecVolumeControlFeatureListener.Stub {
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 c734242..6be28d9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -150,7 +150,7 @@
@Override
public void setAndBroadcastActiveSourceFromOneDeviceType(
- int sourceAddress, int physicalAddress) {
+ int sourceAddress, int physicalAddress, String caller) {
mBroadcastActiveSource = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
deleted file mode 100644
index b6b8b82..0000000
--- a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package com.android.server.location;
-
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-
-import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
-import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-
-/**
- * Unit tests for {@link LocationRequestStatistics}.
- */
-public class LocationRequestStatisticsTest extends AndroidTestCase {
- private static final String PACKAGE1 = "package1";
- private static final String PACKAGE2 = "package2";
- private static final String FEATURE_ID = "featureId";
- private static final String PROVIDER1 = "provider1";
- private static final String PROVIDER2 = "provider2";
- private static final long INTERVAL1 = 5000;
- private static final long INTERVAL2 = 100000;
-
- private LocationRequestStatistics mStatistics;
- private long mStartElapsedRealtimeMs;
-
- @Override
- public void setUp() {
- mStatistics = new LocationRequestStatistics();
- mStartElapsedRealtimeMs = SystemClock.elapsedRealtime();
- }
-
- /**
- * Tests that adding a single package works correctly.
- */
- public void testSinglePackage() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
-
- assertEquals(1, mStatistics.statistics.size());
- PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
- assertEquals(PACKAGE1, key.mPackageName);
- assertEquals(PROVIDER1, key.mProviderName);
- assertEquals(FEATURE_ID, key.mFeatureId);
- PackageStatistics stats = mStatistics.statistics.values().iterator().next();
- verifyStatisticsTimes(stats);
- assertEquals(INTERVAL1, stats.getFastestIntervalMs());
- assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
- assertTrue(stats.isActive());
- }
-
- /**
- * Tests that adding a single package works correctly when it is stopped and restarted.
- */
- public void testSinglePackage_stopAndRestart() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
-
- assertEquals(1, mStatistics.statistics.size());
- PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
- assertEquals(PACKAGE1, key.mPackageName);
- assertEquals(FEATURE_ID, key.mFeatureId);
- assertEquals(PROVIDER1, key.mProviderName);
- PackageStatistics stats = mStatistics.statistics.values().iterator().next();
- verifyStatisticsTimes(stats);
- assertEquals(INTERVAL1, stats.getFastestIntervalMs());
- assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
- assertTrue(stats.isActive());
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- assertFalse(stats.isActive());
- }
-
- /**
- * Tests that adding a single package works correctly when multiple intervals are used.
- */
- public void testSinglePackage_multipleIntervals() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL2, true);
-
- assertEquals(1, mStatistics.statistics.size());
- PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
- assertEquals(PACKAGE1, key.mPackageName);
- assertEquals(PROVIDER1, key.mProviderName);
- assertEquals(FEATURE_ID, key.mFeatureId);
- PackageStatistics stats = mStatistics.statistics.values().iterator().next();
- verifyStatisticsTimes(stats);
- assertEquals(INTERVAL1, stats.getFastestIntervalMs());
- assertTrue(stats.isActive());
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- assertTrue(stats.isActive());
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- assertFalse(stats.isActive());
- }
-
- /**
- * Tests that adding a single package works correctly when multiple providers are used.
- */
- public void testSinglePackage_multipleProviders() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL2, true);
-
- assertEquals(2, mStatistics.statistics.size());
- PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER1);
- PackageStatistics stats1 = mStatistics.statistics.get(key1);
- verifyStatisticsTimes(stats1);
- assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
- assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
- assertTrue(stats1.isActive());
- PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER2);
- PackageStatistics stats2 = mStatistics.statistics.get(key2);
- verifyStatisticsTimes(stats2);
- assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
- assertEquals(INTERVAL2, stats2.getFastestIntervalMs());
- assertTrue(stats2.isActive());
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- assertFalse(stats1.isActive());
- assertTrue(stats2.isActive());
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2);
- assertFalse(stats1.isActive());
- assertFalse(stats2.isActive());
- }
-
- /**
- * Tests that adding multiple packages works correctly.
- */
- public void testMultiplePackages() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL2, true);
- mStatistics.startRequesting(PACKAGE2, FEATURE_ID, PROVIDER1, INTERVAL1, true);
-
- assertEquals(3, mStatistics.statistics.size());
- PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER1);
- PackageStatistics stats1 = mStatistics.statistics.get(key1);
- verifyStatisticsTimes(stats1);
- assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
- assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
- assertTrue(stats1.isActive());
-
- PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER2);
- PackageStatistics stats2 = mStatistics.statistics.get(key2);
- verifyStatisticsTimes(stats2);
- assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
- assertEquals(INTERVAL1, stats2.getFastestIntervalMs());
- assertTrue(stats2.isActive());
-
- PackageProviderKey key3 = new PackageProviderKey(PACKAGE2, FEATURE_ID, PROVIDER1);
- PackageStatistics stats3 = mStatistics.statistics.get(key3);
- verifyStatisticsTimes(stats3);
- assertEquals(INTERVAL1, stats3.getSlowestIntervalMs());
- assertEquals(INTERVAL1, stats3.getFastestIntervalMs());
- assertTrue(stats3.isActive());
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
- assertFalse(stats1.isActive());
- assertTrue(stats2.isActive());
- assertTrue(stats3.isActive());
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2);
- assertFalse(stats1.isActive());
- assertTrue(stats2.isActive());
- assertTrue(stats3.isActive());
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2);
- assertFalse(stats2.isActive());
-
- mStatistics.stopRequesting(PACKAGE2, FEATURE_ID, PROVIDER1);
- assertFalse(stats1.isActive());
- assertFalse(stats2.isActive());
- assertFalse(stats3.isActive());
- }
-
- /**
- * Tests that switching foreground & background states accmulates time reasonably.
- */
- public void testForegroundBackground() {
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL1, true);
- mStatistics.startRequesting(PACKAGE2, FEATURE_ID, PROVIDER1, INTERVAL1, false);
-
- mStatistics.updateForeground(PACKAGE1, FEATURE_ID, PROVIDER2, false);
- mStatistics.updateForeground(PACKAGE2, FEATURE_ID, PROVIDER1, true);
-
- mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1);
-
- for (PackageStatistics stats : mStatistics.statistics.values()) {
- verifyStatisticsTimes(stats);
- }
- }
-
- private void verifyStatisticsTimes(PackageStatistics stats) {
- long durationMs = stats.getDurationMs();
- long foregroundDurationMs = stats.getForegroundDurationMs();
- long timeSinceFirstRequestMs = stats.getTimeSinceFirstRequestMs();
- long maxDeltaMs = SystemClock.elapsedRealtime() - mStartElapsedRealtimeMs;
- assertTrue("Duration is too small", durationMs >= 0);
- assertTrue("Duration is too large", durationMs <= maxDeltaMs);
- assertTrue("Foreground Duration is too small", foregroundDurationMs >= 0);
- assertTrue("Foreground Duration is too large", foregroundDurationMs <= maxDeltaMs);
- assertTrue("Time since first request is too large", timeSinceFirstRequestMs <= maxDeltaMs);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index 631b8d3..292b7c6 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -15,17 +15,22 @@
*/
package com.android.server.location.timezone;
+import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
-import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_DISABLED;
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
import static com.android.server.location.timezone.TestSupport.USER1_ID;
import static com.android.server.location.timezone.TestSupport.USER2_CONFIG_GEO_DETECTION_ENABLED;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -39,6 +44,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.IndentingPrintWriter;
+import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
import com.android.server.timezonedetector.ConfigurationInternal;
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
import com.android.server.timezonedetector.TestState;
@@ -65,10 +71,13 @@
createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_SUCCESS, asList("Europe/Paris"));
private static final LocationTimeZoneEvent USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT =
createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_UNCERTAIN, null);
+ private static final LocationTimeZoneEvent USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT =
+ createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_PERMANENT_FAILURE, null);
private TestThreadingDomain mTestThreadingDomain;
private TestCallback mTestCallback;
- private TestLocationTimeZoneProvider mTestLocationTimeZoneProvider;
+ private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider;
+ private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider;
@Before
public void setUp() {
@@ -77,276 +86,854 @@
// will never get a chance to execute.
mTestThreadingDomain = new TestThreadingDomain();
mTestCallback = new TestCallback(mTestThreadingDomain);
- mTestLocationTimeZoneProvider =
+ mTestPrimaryLocationTimeZoneProvider =
new TestLocationTimeZoneProvider(mTestThreadingDomain, "primary");
+ mTestSecondaryLocationTimeZoneProvider =
+ new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary");
}
@Test
public void initialState_enabled() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
+ .plus(testEnvironment.getProviderInitializationTimeoutFuzz());
+
+ // Initialize. After initialization the providers must be initialized and one should be
+ // enabled.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertInitialized();
+ mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+ mTestSecondaryLocationTimeZoneProvider.assertInitialized();
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void initialState_disabled() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ // Initialize. After initialization the providers must be initialized but neither should be
+ // enabled.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertInitialized();
+ mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+ mTestSecondaryLocationTimeZoneProvider.assertInitialized();
- mTestLocationTimeZoneProvider.assertIsDisabled();
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void enabled_uncertaintySuggestionSentIfNoEventReceived() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate time passing with no event being received.
+ // Simulate time passing with no provider event being received from the primary.
mTestThreadingDomain.executeNext();
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
+ // The primary should have reported uncertainty, which should trigger the controller to
+ // start the uncertainty timeout and enable the secondary.
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate time passing with no provider event being received from either the primary or
+ // secondary.
+ mTestThreadingDomain.executeNext();
+
+ // Now both initialization timeouts should have triggered. The uncertainty timeout should
+ // still not be triggered.
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Finally, the uncertainty timeout should cause the controller to make an uncertain
+ // suggestion.
+ mTestThreadingDomain.executeNext();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertUncertainSuggestionMadeAndCommit();
- mTestThreadingDomain.assertQueueEmpty();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
- public void enabled_uncertaintySuggestionCancelledIfEventReceived() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ public void enabled_eventReceivedBeforeInitializationTimeout() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate a location event being received by the provider. This should cause a suggestion
- // to be made, and the timeout to be cleared.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Simulate a location event being received from the primary provider. This should cause a
+ // suggestion to be made.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
- public void enabled_repeatedCertainty() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ public void enabled_eventReceivedFromPrimaryAfterInitializationTimeout() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate a location event being received by the provider. This should cause a suggestion
- // to be made, and the timeout to be cleared.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Simulate time passing with no provider event being received from the primary.
+ mTestThreadingDomain.executeNext();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate a location event being received from the primary provider. This should cause a
+ // suggestion to be made and the secondary to be shut down.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void enabled_eventReceivedFromSecondaryAfterInitializationTimeout() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate time passing with no provider event being received from the primary.
+ mTestThreadingDomain.executeNext();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate a location event being received from the secondary provider. This should cause a
+ // suggestion to be made.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void enabled_repeatedPrimaryCertainty() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate a location event being received from the primary provider. This should cause a
+ // suggestion to be made.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// A second, identical event should not cause another suggestion.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// And a third, different event should cause another suggestion.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void enabled_repeatedSecondaryCertainty() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate time passing with no provider event being received from the primary.
+ mTestThreadingDomain.executeNext();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate a location event being received from the secondary provider. This should cause a
+ // suggestion to be made.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // A second, identical event should not cause another suggestion.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // And a third, different event should cause another suggestion.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate a location event being received from the primary provider. This should cause a
+ // suggestion to be made and ensure the primary is considered initialized.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate an uncertain event being received from the primary provider. This should not
+ // cause a suggestion to be made straight away, but the uncertainty timeout should be
+ // started and the secondary should be enabled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate a location event being received from the secondary provider. This should cause a
+ // suggestion to be made, cancel the uncertainty timeout and ensure the secondary is
+ // considered initialized.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate an uncertain event being received from the secondary provider. This should not
+ // cause a suggestion to be made straight away, but the uncertainty timeout should be
+ // started. Both providers are now enabled, with no initialization timeout set.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate time passing. This means the uncertainty timeout should fire and the uncertain
+ // suggestion should be made.
+ mTestThreadingDomain.executeNext();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertUncertainSuggestionMadeAndCommit();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void enabled_briefUncertaintyTriggersNoSuggestion() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate a location event being received by the provider. This should cause a suggestion
- // to be made, and the timeout to be cleared.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Simulate a location event being received from the primary provider. This should cause a
+ // suggestion to be made.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Uncertainty should cause a suggestion to (only) be queued.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Uncertainty should not cause a suggestion to be made straight away, but the uncertainty
+ // timeout should be started and the secondary should be enabled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertSingleDelayedQueueItem(testEnvironment.getUncertaintyDelay());
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
- // And a third event should cause yet another suggestion and for the queued item to be
- // removed.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // And a success event from the primary provider should cause the controller to make another
+ // suggestion, the uncertainty timeout should be cancelled and the secondary should be
+ // disabled again.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
- public void configChanges_enableAndDisable() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ public void configChanges_enableAndDisableWithNoPreviousSuggestion() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsDisabled();
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Now signal a config change so that geo detection is enabled.
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Now signal a config change so that geo detection is disabled.
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
- mTestLocationTimeZoneProvider.assertIsDisabled();
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
- public void configChanges_disableWithPreviousSuggestion() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ public void configChanges_enableAndDisableWithPreviousSuggestion() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
- mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate a location event being received by the provider. This should cause a suggestion
- // to be made, and the timeout to be cleared.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Now signal a config change so that geo detection is enabled.
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate a success event being received from the primary provider.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate the user disabling the provider.
- testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
-
+ // Now signal a config change so that geo detection is disabled.
// Because there had been a previous suggestion, the controller should withdraw it
// immediately to let the downstream components know that the provider can no longer be sure
// of the time zone.
- mTestLocationTimeZoneProvider.assertIsDisabled();
- mTestThreadingDomain.assertQueueEmpty();
- mTestCallback.assertSuggestionMadeAndCommit(null);
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertUncertainSuggestionMadeAndCommit();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void configChanges_userSwitch_enabledToEnabled() {
- ControllerImpl controllerImpl =
- new ControllerImpl(mTestThreadingDomain, mTestLocationTimeZoneProvider);
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
- // There should be a runnable scheduled to suggest uncertainty if no event is received.
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- Duration expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Have the provider suggest a time zone.
- mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ // Simulate the primary provider suggesting a time zone.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
// Receiving a "success" provider event should cause a suggestion to be made synchronously,
// and also clear the scheduled uncertainty suggestion.
- mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate the user change (but geo detection still enabled).
testEnvironment.simulateConfigChange(USER2_CONFIG_GEO_DETECTION_ENABLED);
// We expect the provider to end up in PROVIDER_STATE_ENABLED, but it should have been
// disabled when the user changed.
- // The controller should schedule a runnable to make a suggestion if the provider doesn't
- // send a success event.
- int[] expectedStateTransitions = { PROVIDER_STATE_DISABLED, PROVIDER_STATE_ENABLED };
- mTestLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions);
- mTestLocationTimeZoneProvider.assertConfig(USER2_CONFIG_GEO_DETECTION_ENABLED);
- expectedTimeout = expectedProviderInitializationTimeout();
- mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout);
+ int[] expectedStateTransitions =
+ { PROVIDER_STATE_DISABLED, PROVIDER_STATE_ENABLED_INITIALIZING };
+ mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions);
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void primaryPermFailure_secondaryEventsReceived() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
- // Simulate no event being received, and time passing.
- mTestThreadingDomain.executeNext();
+ // Simulate a failure location event being received from the primary provider. This should
+ // cause the secondary to be enabled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
- mTestLocationTimeZoneProvider.assertIsEnabled(USER2_CONFIG_GEO_DETECTION_ENABLED);
- mTestThreadingDomain.assertQueueEmpty();
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate uncertainty from the secondary.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // And a success event from the secondary provider should cause the controller to make
+ // another suggestion, the uncertainty timeout should be cancelled.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate uncertainty from the secondary.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+ }
+
+ @Test
+ public void primaryPermFailure_disableAndEnable() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate a failure location event being received from the primary provider. This should
+ // cause the secondary to be enabled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Now signal a config change so that geo detection is disabled.
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Now signal a config change so that geo detection is enabled.
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void secondaryPermFailure_primaryEventsReceived() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate an uncertain event from the primary. This will enable the secondary, which will
+ // give this test the opportunity to simulate its failure. Then it will be possible to
+ // demonstrate controller behavior with only the primary working.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate failure event from the secondary. This should just affect the secondary's state.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // And a success event from the primary provider should cause the controller to make
+ // a suggestion, the uncertainty timeout should be cancelled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate uncertainty from the primary. The secondary cannot be enabled.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+ }
+
+ @Test
+ public void secondaryPermFailure_disableAndEnable() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate an uncertain event from the primary. This will enable the secondary, which will
+ // give this test the opportunity to simulate its failure. Then it will be possible to
+ // demonstrate controller behavior with only the primary working.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Simulate failure event from the secondary. This should just affect the secondary's state.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+ // Now signal a config change so that geo detection is disabled.
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Now signal a config change so that geo detection is enabled. Only the primary can be
+ // enabled.
+ testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ @Test
+ public void bothPermFailure_disableAndEnable() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate a failure event from the primary. This will enable the secondary.
+ mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate failure event from the secondary.
+ mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+ USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+ mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+ mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertUncertainSuggestionMadeAndCommit();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
+ private static void assertUncertaintyTimeoutSet(
+ LocationTimeZoneProviderController.Environment environment,
+ LocationTimeZoneProviderController controller) {
+ assertTrue(controller.isUncertaintyTimeoutSet());
+ assertEquals(environment.getUncertaintyDelay().toMillis(),
+ controller.getUncertaintyTimeoutDelayMillis());
}
private static LocationTimeZoneEvent createLocationTimeZoneEvent(@UserIdInt int userId,
@@ -362,16 +949,15 @@
}
- private Duration expectedProviderInitializationTimeout() {
- return TestEnvironment.PROVIDER_INITIALIZATION_TIMEOUT
- .plus(TestEnvironment.PROVIDER_INITIALIZATION_TIMEOUT_FUZZ);
- }
-
private static class TestEnvironment extends LocationTimeZoneProviderController.Environment {
+ // These timeouts are set deliberately so that:
+ // (initialization timeout * 2) < uncertainty delay
+ //
+ // That makes the order of initialization timeout Vs uncertainty delay deterministic.
static final Duration PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(5);
static final Duration PROVIDER_INITIALIZATION_TIMEOUT_FUZZ = Duration.ofMinutes(1);
- private static final Duration UNCERTAINTY_DELAY = Duration.ofMinutes(3);
+ private static final Duration UNCERTAINTY_DELAY = Duration.ofMinutes(15);
private final LocationTimeZoneProviderController mController;
private ConfigurationInternal mConfigurationInternal;
@@ -491,38 +1077,57 @@
assertTrue(mInitialized);
}
- void assertIsDisabled() {
- // Disabled providers don't hold config.
- assertConfig(null);
- assertIsEnabledAndCommit(false);
- }
-
- /**
- * Asserts the provider's config matches the expected, and the current state is set
- * accordingly. Commits the latest changes to the state.
- */
- void assertIsEnabled(@NonNull ConfigurationInternal expectedConfig) {
- assertConfig(expectedConfig);
-
- boolean expectIsEnabled = expectedConfig.getAutoDetectionEnabledBehavior();
- assertIsEnabledAndCommit(expectIsEnabled);
- }
-
- private void assertIsEnabledAndCommit(boolean enabled) {
- ProviderState currentState = mCurrentState.get();
- if (enabled) {
- assertEquals(PROVIDER_STATE_ENABLED, currentState.stateEnum);
- } else {
- assertEquals(PROVIDER_STATE_DISABLED, currentState.stateEnum);
- }
+ public void assertIsPermFailedAndCommit() {
+ // A failed provider doesn't hold config.
+ assertStateEnumAndConfig(PROVIDER_STATE_PERM_FAILED, null /* config */);
mTestProviderState.commitLatest();
}
- void assertConfig(@NonNull ConfigurationInternal expectedConfig) {
+ void assertIsDisabledAndCommit() {
+ // A disabled provider doesn't hold config.
+ assertStateEnumAndConfig(PROVIDER_STATE_DISABLED, null /* config */);
+ mTestProviderState.commitLatest();
+ }
+
+ /**
+ * Asserts the provider's state enum and config matches the expected.
+ * Commits the latest changes to the state.
+ */
+ void assertStateEnumAndConfigAndCommit(
+ @ProviderStateEnum int expectedStateEnum,
+ @Nullable ConfigurationInternal expectedConfig) {
+ assertStateEnumAndConfig(expectedStateEnum, expectedConfig);
+ mTestProviderState.commitLatest();
+ }
+
+ /**
+ * Asserts the provider's state enum and config matches the expected.
+ * Does not commit any state changes.
+ */
+ void assertStateEnumAndConfig(
+ @ProviderStateEnum int expectedStateEnum,
+ @Nullable ConfigurationInternal expectedConfig) {
+ ProviderState currentState = mCurrentState.get();
+ assertEquals(expectedStateEnum, currentState.stateEnum);
+
+ // If and only if the controller is initializing, the initialization timeout must be
+ // set.
+ assertEquals(expectedStateEnum == PROVIDER_STATE_ENABLED_INITIALIZING,
+ isInitializationTimeoutSet());
+
+ assertConfig(expectedConfig);
+ }
+
+ private void assertConfig(@Nullable ConfigurationInternal expectedConfig) {
ProviderState currentState = mCurrentState.get();
assertEquals(expectedConfig, currentState.currentUserConfiguration);
}
+ void assertInitializationTimeoutSet(Duration expectedTimeout) {
+ assertTrue(isInitializationTimeoutSet());
+ assertEquals(expectedTimeout, getInitializationTimeoutDelay());
+ }
+
void simulateLocationTimeZoneEvent(@NonNull LocationTimeZoneEvent event) {
handleLocationTimeZoneEvent(event);
}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/HandlerThreadingDomainTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/HandlerThreadingDomainTest.java
index cbaf0f3..4d6775d 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/HandlerThreadingDomainTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/HandlerThreadingDomainTest.java
@@ -115,28 +115,7 @@
}
@Test
- public void singleRunnableHandler_runSynchronously() throws Exception {
- ThreadingDomain domain = new HandlerThreadingDomain(mTestHandler);
- SingleRunnableQueue singleRunnableQueue = domain.createSingleRunnableQueue();
-
- AtomicBoolean testPassed = new AtomicBoolean(false);
- // Calls to SingleRunnableQueue must be made on the handler thread it is associated with,
- // so this uses runWithScissors() to block until the lambda has completed.
- mTestHandler.runWithScissors(() -> {
- Thread testThread = Thread.currentThread();
- CountDownLatch latch = new CountDownLatch(1);
- singleRunnableQueue.runSynchronously(() -> {
- assertSame(Thread.currentThread(), testThread);
- latch.countDown();
- });
- assertTrue(awaitWithRuntimeException(latch, 60, TimeUnit.SECONDS));
- testPassed.set(true);
- }, TimeUnit.SECONDS.toMillis(60));
- assertTrue(testPassed.get());
- }
-
- @Test
- public void singleRunnableHandler_runDelayed() throws Exception {
+ public void singleRunnableQueue_runDelayed() throws Exception {
ThreadingDomain domain = new HandlerThreadingDomain(mTestHandler);
SingleRunnableQueue singleRunnableQueue = domain.createSingleRunnableQueue();
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java
index 5542db0..5403a65 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java
@@ -16,7 +16,7 @@
package com.android.server.location.timezone;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
-import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
@@ -76,15 +76,16 @@
ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
- provider.enable(config, arbitraryInitializationTimeout);
+ Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2);
+ provider.enable(config, arbitraryInitializationTimeout, arbitraryInitializationTimeoutFuzz);
- // The StubbedProvider should enters enabled state, but immediately schedule a runnable to
- // switch to perm failure.
+ // The NullProvider should enter the enabled state, but have schedule an immediate runnable
+ // to switch to perm failure.
ProviderState currentState = provider.getCurrentState();
assertSame(provider, currentState.provider);
- assertEquals(PROVIDER_STATE_ENABLED, currentState.stateEnum);
+ assertEquals(PROVIDER_STATE_ENABLED_INITIALIZING, currentState.stateEnum);
assertEquals(config, currentState.currentUserConfiguration);
- mTestThreadingDomain.assertSingleImmediateQueueItem();
+ mTestThreadingDomain.assertNextQueueItemIsImmediate();
// Entering enabled() does not trigger an onProviderStateChanged() as it is requested by the
// controller.
mTestController.assertProviderChangeNotTriggered();
@@ -116,6 +117,18 @@
// Not needed for provider testing.
}
+ @Override
+ boolean isUncertaintyTimeoutSet() {
+ // Not needed for provider testing.
+ return false;
+ }
+
+ @Override
+ long getUncertaintyTimeoutDelayMillis() {
+ // Not needed for provider testing.
+ return 0;
+ }
+
void onProviderStateChange(ProviderState providerState) {
this.mProviderState.set(providerState);
}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java b/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java
index def919e..7359abd 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java
@@ -16,13 +16,15 @@
package com.android.server.location.timezone;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.annotation.Nullable;
import java.time.Duration;
-import java.util.LinkedList;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.Objects;
/**
@@ -33,6 +35,10 @@
class TestThreadingDomain extends ThreadingDomain {
static class QueuedRunnable {
+
+ static final Comparator<? super QueuedRunnable> COMPARATOR =
+ (o1, o2) -> (int) (o1.executionTimeMillis - o2.executionTimeMillis);
+
@NonNull public final Runnable runnable;
@Nullable public final Object token;
public final long executionTimeMillis;
@@ -55,7 +61,7 @@
}
private long mCurrentTimeMillis;
- private LinkedList<QueuedRunnable> mQueue = new LinkedList<>();
+ private ArrayList<QueuedRunnable> mQueue = new ArrayList<>();
TestThreadingDomain() {
// Pick an arbitrary time.
@@ -69,22 +75,23 @@
@Override
void post(Runnable r) {
- mQueue.add(new QueuedRunnable(r, null, mCurrentTimeMillis));
+ postDelayed(r, null, 0);
}
@Override
void postDelayed(Runnable r, long delayMillis) {
- mQueue.add(new QueuedRunnable(r, null, mCurrentTimeMillis + delayMillis));
+ postDelayed(r, null, delayMillis);
}
@Override
void postDelayed(Runnable r, Object token, long delayMillis) {
mQueue.add(new QueuedRunnable(r, token, mCurrentTimeMillis + delayMillis));
+ mQueue.sort(QueuedRunnable.COMPARATOR);
}
@Override
void removeQueuedRunnables(Object token) {
- mQueue.removeIf(runnable -> runnable.token != null && runnable.token.equals(token));
+ mQueue.removeIf(runnable -> runnable.token != null && runnable.token == token);
}
void assertSingleDelayedQueueItem(Duration expectedDelay) {
@@ -114,14 +121,14 @@
}
long getNextQueueItemDelayMillis() {
- assertQueueLength(1);
- return mQueue.getFirst().executionTimeMillis - mCurrentTimeMillis;
+ assertFalse(mQueue.isEmpty());
+ return mQueue.get(0).executionTimeMillis - mCurrentTimeMillis;
}
void executeNext() {
- assertQueueLength(1);
+ assertFalse(mQueue.isEmpty());
+ QueuedRunnable queued = mQueue.remove(0);
- QueuedRunnable queued = mQueue.removeFirst();
mCurrentTimeMillis = queued.executionTimeMillis;
queued.runnable.run();
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index d7ed96f..54b5bee 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -16,22 +16,23 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.app.timezonedetector.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import org.junit.Test;
/**
- * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and
- * {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it.
+ * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilitiesAndConfig}.
*/
public class ConfigurationInternalTest {
@@ -59,13 +60,20 @@
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
- assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOnConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_APPLICABLE,
+ capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
{
@@ -77,13 +85,20 @@
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
- assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOffConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED,
+ capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
}
@@ -106,13 +121,20 @@
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
- assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOnConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
{
@@ -124,13 +146,20 @@
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
- assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOffConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_ALLOWED,
+ capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
}
@@ -153,13 +182,19 @@
assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
- assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOnConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertTrue(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
@@ -170,13 +205,19 @@
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
- TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
- assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
- assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ autoOffConfig.createCapabilitiesAndConfig();
+
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureAutoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_NOT_SUPPORTED,
+ capabilities.getConfigureGeoDetectionEnabledCapability());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZoneCapability());
+
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ assertFalse(configuration.isAutoDetectionEnabled());
+ assertTrue(configuration.isGeoDetectionEnabled());
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index 4ef2082..bad380a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -22,10 +22,11 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
import java.util.ArrayList;
@@ -67,20 +68,25 @@
}
@Override
- public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) {
+ public boolean updateConfiguration(
+ @UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges) {
assertNotNull(mConfigurationInternal);
assertNotNull(requestedChanges);
// Simulate the real strategy's behavior: the new configuration will be updated to be the
// old configuration merged with the new if the user has the capability to up the settings.
// Then, if the configuration changed, the change listener is invoked.
- TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities();
- TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges);
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ mConfigurationInternal.createCapabilitiesAndConfig();
+ TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ TimeZoneConfiguration newConfiguration =
+ capabilities.tryApplyConfigChanges(configuration, requestedChanges);
if (newConfiguration == null) {
return false;
}
- if (!newConfiguration.equals(capabilities.getConfiguration())) {
+ if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
// Note: Unlike the real strategy, the listeners is invoked synchronously.
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 27b04b6..cb27657 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -31,10 +31,10 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.app.timezonedetector.ITimeZoneConfigurationListener;
+import android.app.time.ITimeZoneDetectorListener;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
@@ -91,85 +91,85 @@
}
@Test(expected = SecurityException.class)
- public void testGetCapabilities_withoutPermission() {
+ public void testGetCapabilitiesAndConfig_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
try {
- mTimeZoneDetectorService.getCapabilities();
+ mTimeZoneDetectorService.getCapabilitiesAndConfig();
fail();
} finally {
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
}
}
@Test
- public void testGetCapabilities() {
+ public void testGetCapabilitiesAndConfig() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
ConfigurationInternal configuration =
createConfigurationInternal(true /* autoDetectionEnabled*/);
mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
- assertEquals(configuration.createCapabilities(),
- mTimeZoneDetectorService.getCapabilities());
+ assertEquals(configuration.createCapabilitiesAndConfig(),
+ mTimeZoneDetectorService.getCapabilitiesAndConfig());
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
}
@Test(expected = SecurityException.class)
- public void testAddConfigurationListener_withoutPermission() {
+ public void testAddListener_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
+ ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
try {
- mTimeZoneDetectorService.addConfigurationListener(mockListener);
+ mTimeZoneDetectorService.addListener(mockListener);
fail();
} finally {
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
}
}
@Test(expected = SecurityException.class)
- public void testRemoveConfigurationListener_withoutPermission() {
+ public void testRemoveListener_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
+ ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
try {
- mTimeZoneDetectorService.removeConfigurationListener(mockListener);
+ mTimeZoneDetectorService.removeListener(mockListener);
fail("Expected a SecurityException");
} finally {
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
}
}
@Test
- public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception {
+ public void testListenerRegistrationAndCallbacks() throws Exception {
ConfigurationInternal initialConfiguration =
createConfigurationInternal(false /* autoDetectionEnabled */);
mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
- ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
+ ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
{
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
when(mockListener.asBinder()).thenReturn(mockListenerBinder);
- mTimeZoneDetectorService.addConfigurationListener(mockListener);
+ mTimeZoneDetectorService.addListener(mockListener);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
verify(mockListener).asBinder();
verify(mockListenerBinder).linkToDeath(any(), anyInt());
@@ -186,7 +186,7 @@
mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
verify(mockListener).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
@@ -200,10 +200,10 @@
// Now remove the listener, change the config again, and verify the listener is not
// called.
- mTimeZoneDetectorService.removeConfigurationListener(mockListener);
+ mTimeZoneDetectorService.removeListener(mockListener);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
verify(mockListener).asBinder();
verify(mockListenerBinder).unlinkToDeath(any(), eq(0));
@@ -219,7 +219,7 @@
mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
+ eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
anyString());
verify(mockListener, never()).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
@@ -354,7 +354,7 @@
}
private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
- return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ return new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(autoDetectionEnabled)
.build();
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 1cdf193..296aa73 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -39,11 +39,11 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
@@ -186,26 +186,27 @@
Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Set the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
// Nothing should have happened: it was initialized in this state.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
@@ -216,20 +217,22 @@
Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Try to update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -240,13 +243,15 @@
Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -389,7 +394,8 @@
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting on should cause the device setting to be set.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
// When time zone detection is already enabled the suggestion (if it scores highly
// enough) should be set immediately.
@@ -406,7 +412,8 @@
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting should off should do nothing.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Assert internal service state.
@@ -588,18 +595,20 @@
// Toggling time zone detection should set the device time zone only if the current setting
// value is different from the most recent telephony suggestion.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Simulate a user turning auto detection off, a new suggestion being made while auto
// detection is off, and the user turning it on again.
- script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
.verifyTimeZoneNotChanged();
// Latest suggestion should be used.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(newYorkSuggestion);
}
@@ -784,7 +793,7 @@
assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
// Turn off geo detection and verify the latest suggestion is cleared.
- script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_GEO_DETECTION_DISABLED, true)
.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Assert internal service state.
@@ -824,19 +833,21 @@
// Toggling the time zone detection enabled setting on should cause the device setting to be
// set from the telephony signal, as we've started with geolocation time zone detection
// disabled.
- script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
// Changing the detection to enable geo detection won't cause the device tz setting to
// change because the geo suggestion is empty.
- script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged()
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
.verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
// Changing the detection to disable geo detection should cause the device tz setting to
// change to the telephony suggestion.
- script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
@@ -898,7 +909,7 @@
private static TimeZoneConfiguration createConfig(
@Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
- TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID);
+ TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder();
if (autoDetection != null) {
builder.setAutoDetectionEnabled(autoDetection);
}
@@ -957,9 +968,10 @@
}
@Override
- public void storeConfiguration(TimeZoneConfiguration newConfiguration) {
+ public void storeConfiguration(
+ @UserIdInt int userId, TimeZoneConfiguration newConfiguration) {
ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
- if (newConfiguration.getUserId() != oldConfiguration.getUserId()) {
+ if (userId != oldConfiguration.getUserId()) {
fail("FakeCallback does not support multiple users");
}
@@ -1014,9 +1026,9 @@
* the return value.
*/
Script simulateUpdateConfiguration(
- TimeZoneConfiguration configuration, boolean expectedResult) {
+ int userId, TimeZoneConfiguration configuration, boolean expectedResult) {
assertEquals(expectedResult,
- mTimeZoneDetectorStrategy.updateConfiguration(configuration));
+ mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
return this;
}
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 2c64526..0c6d638 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -84,6 +84,7 @@
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -703,6 +704,7 @@
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
}
+ @Ignore
@Test
public void testPredictionTimedOut() throws Exception {
// Set it to timeout or usage, so that prediction can override it
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 3af873d..dd85484 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1126,7 +1126,7 @@
// Verify the stack-top activity is occluded keyguard.
assertEquals(topActivity, mStack.topRunningActivity());
- assertTrue(mStack.topActivityOccludesKeyguard());
+ assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
// Finish the top activity
topActivity.setState(PAUSED, "true");
@@ -1135,7 +1135,7 @@
// Verify new top activity does not occlude keyguard.
assertEquals(mActivity, mStack.topRunningActivity());
- assertFalse(mStack.topActivityOccludesKeyguard());
+ assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
new file mode 100644
index 0000000..9a668b9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link DisplayAreaGroup} container.
+ *
+ * Build/Install/Run:
+ * atest WmTests:DisplayAreaGroupTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class DisplayAreaGroupTest extends WindowTestsBase {
+
+ private DisplayAreaGroup mDisplayAreaGroup;
+ private TaskDisplayArea mTaskDisplayArea;
+ private Task mStack;
+ private ActivityRecord mActivity;
+
+ @Before
+ public void setUp() {
+ mDisplayAreaGroup = new DisplayAreaGroup(
+ mWm, "DisplayAreaGroup", FEATURE_VENDOR_FIRST);
+ final TaskDisplayArea defaultTda = mDisplayContent.getDefaultTaskDisplayArea();
+ final WindowContainer parentDA = defaultTda.getParent();
+ parentDA.addChild(mDisplayAreaGroup, parentDA.mChildren.indexOf(defaultTda) + 1);
+ mTaskDisplayArea = new TaskDisplayArea(
+ mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1);
+ mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
+ mStack = mTaskDisplayArea.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ mActivity = new ActivityBuilder(mAtm).setCreateTask(true).setStack(mStack).build();
+ mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
+ }
+
+ @Test
+ public void testIsOrientationDifferentFromDisplay() {
+ // Display is portrait, DisplayAreaGroup inherits that
+ mDisplayContent.setBounds(0, 0, 600, 900);
+
+ assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();
+
+ // DisplayAreaGroup is landscape, different Display
+ mDisplayAreaGroup.setBounds(0, 0, 600, 450);
+
+ assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isTrue();
+
+ // DisplayAreaGroup is portrait, same as Display
+ mDisplayAreaGroup.setBounds(0, 0, 300, 900);
+
+ assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();
+ }
+
+ @Test
+ public void testGetOrientation() {
+ doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ // Display is portrait, DisplayAreaGroup inherits that
+ mDisplayContent.setBounds(0, 0, 600, 900);
+
+ assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(mActivity.getRequestedConfigurationOrientation())
+ .isEqualTo(ORIENTATION_PORTRAIT);
+
+ // DisplayAreaGroup is landscape, different from Display
+ mDisplayAreaGroup.setBounds(0, 0, 600, 450);
+
+ assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+ assertThat(mActivity.getRequestedConfigurationOrientation())
+ .isEqualTo(ORIENTATION_LANDSCAPE);
+
+ // DisplayAreaGroup is portrait, same as Display
+ mDisplayAreaGroup.setBounds(0, 0, 300, 900);
+
+ assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(mActivity.getRequestedConfigurationOrientation())
+ .isEqualTo(ORIENTATION_PORTRAIT);
+ }
+}
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 633d216..4a90466 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1349,6 +1349,27 @@
}
@Test
+ public void testNoFixedRotationOnResumedScheduledApp() {
+ unblockDisplayRotation(mDisplayContent);
+ final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ app.setVisible(false);
+ app.setState(Task.ActivityState.RESUMED, "test");
+ mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
+ false /* alwaysKeepCurrent */);
+ mDisplayContent.mOpeningApps.add(app);
+ final int newOrientation = getRotatedOrientation(mDisplayContent);
+ app.setRequestedOrientation(newOrientation);
+
+ // The condition should reject using fixed rotation because the resumed client in real case
+ // might get display info immediately. And the fixed rotation adjustments haven't arrived
+ // client side so the info may be inconsistent with the requested orientation.
+ verify(mDisplayContent).handleTopActivityLaunchingInDifferentOrientation(eq(app),
+ eq(true) /* checkOpening */);
+ assertFalse(app.isFixedRotationTransforming());
+ assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
+ }
+
+ @Test
public void testRecentsNotRotatingWithFixedRotation() {
unblockDisplayRotation(mDisplayContent);
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 820eca4..bc7516f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
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_SECONDARY;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -319,6 +320,29 @@
}
/**
+ * Ensures that {@link LaunchParamsModifier} doesn't alter non-root tasks' windowingMode.
+ */
+ @Test
+ public void testLayoutNonRootTaskWindowingModeChange() {
+ final LaunchParams params = new LaunchParams();
+ final int windowingMode = WINDOWING_MODE_FREEFORM;
+ params.mWindowingMode = windowingMode;
+ final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).setCreateParentTask(true).build();
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+
+ mController.registerModifier(positioner);
+
+ final int beforeWindowMode = task.getWindowingMode();
+ assertNotEquals(windowingMode, beforeWindowMode);
+
+ mController.layoutTask(task, null /* windowLayout */);
+
+ final int afterWindowMode = task.getWindowingMode();
+ assertEquals(afterWindowMode, beforeWindowMode);
+ }
+
+ /**
* Ensures that {@link LaunchParamsModifier} requests specifying bounds during
* layout are honored if window is in freeform.
*/
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 58d994c..7a30c37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -44,7 +44,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -292,8 +291,7 @@
mRecentTasks.add(mTasks.get(1));
invocation.callRealMethod();
return null;
- }).when(mSupervisor).endActivityVisibilityUpdate(any(), anyInt(), anyBoolean(),
- anyBoolean());
+ }).when(mSupervisor).endActivityVisibilityUpdate();
mTaskContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, false /* notifyClients */);
@@ -1190,7 +1188,7 @@
() -> mAtm.unregisterTaskStackListener(null));
assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
- assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, null,
+ assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, 0,
null));
assertSecurityException(expectCallable, () -> mAtm.cancelRecentsAnimation(true));
assertSecurityException(expectCallable, () -> mAtm.stopAppSwitches());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index d821d38..c10d4fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -147,7 +147,7 @@
Intent recentsIntent = new Intent().setComponent(mRecentsComponent);
// Null animation indicates to preload.
- mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
null /* recentsAnimationRunner */);
Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
@@ -167,7 +167,7 @@
spyOn(recentsActivity);
// Start when the recents activity exists. It should ensure the configuration.
- mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
null /* recentsAnimationRunner */);
verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
@@ -381,7 +381,7 @@
Intent recentsIntent = new Intent();
recentsIntent.setComponent(recentsComponent);
- mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
mock(IRecentsAnimationRunner.class));
return recentsAnimation[0];
}
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 d7eedd9..d0a5644 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -147,13 +147,6 @@
}
@Override
- public SurfaceControl.Transaction deferTransactionUntilSurface(SurfaceControl sc,
- Surface barrierSurface,
- long frameNumber) {
- return this;
- }
-
- @Override
public SurfaceControl.Transaction reparentChildren(SurfaceControl sc,
SurfaceControl newParent) {
return this;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
new file mode 100644
index 0000000..ce22205
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -0,0 +1,178 @@
+/*
+ * 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.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+import android.window.ITaskOrganizer;
+import android.window.TransitionInfo;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest WmTests:TransitionRecordTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class TransitionTests extends WindowTestsBase {
+
+ @Test
+ public void testCreateInfo_NewTask() {
+ final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task oldTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ newTask.setHasBeenVisible(true);
+ oldTask.setHasBeenVisible(false);
+ final ActivityRecord closing = createActivityRecordInTask(oldTask);
+ final ActivityRecord opening = createActivityRecordInTask(newTask);
+ closing.setVisible(true);
+ closing.mVisibleRequested = false;
+ opening.setVisible(false);
+ opening.mVisibleRequested = true;
+ ArrayMap<WindowContainer, Transition.ChangeInfo> participants = new ArrayMap<>();
+
+ int transitType = TRANSIT_TASK_OPEN;
+
+ // Check basic both tasks participating
+ participants.put(oldTask, new Transition.ChangeInfo());
+ participants.put(newTask, new Transition.ChangeInfo());
+ TransitionInfo info =
+ Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transitType, info.getType());
+
+ // Check that children are pruned
+ participants.put(opening, new Transition.ChangeInfo());
+ participants.put(closing, new Transition.ChangeInfo());
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
+
+ // Check combined prune and promote
+ participants.remove(newTask);
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
+
+ // Check multi promote
+ participants.remove(oldTask);
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
+ }
+
+ @Test
+ public void testCreateInfo_NestedTasks() {
+ final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task newNestedTask = createTaskInStack(newTask, 0);
+ final Task newNestedTask2 = createTaskInStack(newTask, 0);
+ final Task oldTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ newTask.setHasBeenVisible(true);
+ oldTask.setHasBeenVisible(false);
+ final ActivityRecord closing = createActivityRecordInTask(oldTask);
+ final ActivityRecord opening = createActivityRecordInTask(newNestedTask);
+ final ActivityRecord opening2 = createActivityRecordInTask(newNestedTask2);
+ closing.setVisible(true);
+ closing.mVisibleRequested = false;
+ opening.setVisible(false);
+ opening.mVisibleRequested = true;
+ opening2.setVisible(false);
+ opening2.mVisibleRequested = true;
+ ArrayMap<WindowContainer, Transition.ChangeInfo> participants = new ArrayMap<>();
+
+ int transitType = TRANSIT_TASK_OPEN;
+
+ // Check full promotion from leaf
+ participants.put(oldTask, new Transition.ChangeInfo());
+ participants.put(opening, new Transition.ChangeInfo());
+ participants.put(opening2, new Transition.ChangeInfo());
+ TransitionInfo info =
+ Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transitType, info.getType());
+ assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
+
+ // Check that unchanging but visible descendant of sibling prevents promotion
+ participants.remove(opening2);
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertNotNull(info.getChange(newNestedTask.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
+ }
+
+ @Test
+ public void testCreateInfo_DisplayArea() {
+ final Task showTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task showNestedTask = createTaskInStack(showTask, 0);
+ final Task showTask2 = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final DisplayArea tda = showTask.getDisplayArea();
+ showTask.setHasBeenVisible(true);
+ showTask2.setHasBeenVisible(true);
+ final ActivityRecord showing = createActivityRecordInTask(showNestedTask);
+ final ActivityRecord showing2 = createActivityRecordInTask(showTask2);
+ showing.setVisible(false);
+ showing.mVisibleRequested = true;
+ showing2.setVisible(false);
+ showing2.mVisibleRequested = true;
+ ArrayMap<WindowContainer, Transition.ChangeInfo> participants = new ArrayMap<>();
+
+ int transitType = TRANSIT_TASK_OPEN;
+
+ // Check promotion to DisplayArea
+ participants.put(showing, new Transition.ChangeInfo());
+ participants.put(showing2, new Transition.ChangeInfo());
+ TransitionInfo info =
+ Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(1, info.getChanges().size());
+ assertEquals(transitType, info.getType());
+ assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
+
+ ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
+ // Check that organized tasks get reported even if not top
+ showTask.mTaskOrganizer = mockOrg;
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
+ assertNotNull(info.getChange(showTask.mRemoteToken.toWindowContainerToken()));
+ // Even if DisplayArea explicitly participating
+ participants.put(tda, new Transition.ChangeInfo());
+ info = Transition.calculateTransitionInfo(transitType, participants);
+ assertEquals(2, info.getChanges().size());
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 986807e..6237be0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -265,6 +265,11 @@
return activity;
}
+ /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */
+ static ActivityRecord createActivityRecordInTask(Task task) {
+ return createActivityRecordInTask(task.getDisplayContent(), task);
+ }
+
static ActivityRecord createTestActivityRecord(DisplayContent dc) {
final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
postCreateActivitySetup(activity, dc);
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 4a3561b..866e171 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -49,12 +49,11 @@
public final class PhoneAccount implements Parcelable {
/**
- * String extra which determines the order in which {@link PhoneAccount}s are sorted
+ * Integer extra which determines the order in which {@link PhoneAccount}s are sorted
*
* This is an extras key set via {@link Builder#setExtras} which determines the order in which
* {@link PhoneAccount}s from the same {@link ConnectionService} are sorted. The accounts
- * are sorted by this key via standard lexicographical order, (as implemented in
- * {@link String#compareTo}), and this ordering is used to
+ * are sorted in ascending order by this key, and this ordering is used to
* determine priority when a call can be placed via multiple accounts.
*
* When multiple {@link PhoneAccount}s are supplied with the same sort order key, no ordering is
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 72a739c..3ff48ce 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -35,16 +35,12 @@
method public int getTimeoutSeconds();
method public boolean isEnabled();
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
- field public static final int ERROR_FDN_CHECK_FAILURE = 2; // 0x2
- field public static final int ERROR_NOT_SUPPORTED = 3; // 0x3
- field public static final int ERROR_UNKNOWN = 1; // 0x1
field public static final int REASON_ALL = 4; // 0x4
field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
field public static final int REASON_BUSY = 1; // 0x1
field public static final int REASON_NOT_REACHABLE = 3; // 0x3
field public static final int REASON_NO_REPLY = 2; // 0x2
field public static final int REASON_UNCONDITIONAL = 0; // 0x0
- field public static final int SUCCESS = 0; // 0x0
}
public final class CallQuality implements android.os.Parcelable {
@@ -698,6 +694,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
@@ -755,7 +752,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingStatus(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
@@ -854,6 +851,10 @@
public static interface TelephonyManager.CallForwardingInfoCallback {
method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo);
method public void onError(int);
+ field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 2; // 0x2
+ field public static final int RESULT_ERROR_NOT_SUPPORTED = 3; // 0x3
+ field public static final int RESULT_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 0; // 0x0
}
public final class UiccAccessRule implements android.os.Parcelable {
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index b35b323..c3cd017 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -524,7 +524,7 @@
}
private static String getDefaultSmsPackage(Context context, int userId) {
- return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId);
+ return context.getSystemService(RoleManager.class).getSmsRoleHolder(userId);
}
/**
diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java
index 2106f7f..6ae6d00 100644
--- a/telephony/java/android/telephony/CallForwardingInfo.java
+++ b/telephony/java/android/telephony/CallForwardingInfo.java
@@ -39,27 +39,6 @@
private static final String TAG = "CallForwardingInfo";
/**
- * Indicates that the operation was successful.
- */
- public static final int SUCCESS = 0;
-
- /**
- * Indicates that setting or retrieving the call forwarding info failed with an unknown error.
- */
- public static final int ERROR_UNKNOWN = 1;
-
- /**
- * Indicates that call forwarding is not enabled because the recipient is not on a
- * Fixed Dialing Number (FDN) list.
- */
- public static final int ERROR_FDN_CHECK_FAILURE = 2;
-
- /**
- * Indicates that call forwarding is not supported on the network at this time.
- */
- public static final int ERROR_NOT_SUPPORTED = 3;
-
- /**
* Indicates that call forwarding reason is "unconditional".
* Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
* and conditions +CCFC
@@ -104,19 +83,6 @@
public static final int REASON_ALL_CONDITIONAL = 5;
/**
- * Call forwarding errors
- * @hide
- */
- @IntDef(prefix = { "ERROR_" }, value = {
- ERROR_UNKNOWN,
- ERROR_NOT_SUPPORTED,
- ERROR_FDN_CHECK_FAILURE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CallForwardingError{
- }
-
- /**
* Call forwarding reason types
* @hide
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7a0e1cd..12e56cc 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -12955,6 +12955,40 @@
@SystemApi
public interface CallForwardingInfoCallback {
/**
+ * Indicates that the operation was successful.
+ */
+ int RESULT_SUCCESS = 0;
+
+ /**
+ * Indicates that setting or retrieving the call forwarding info failed with an unknown
+ * error.
+ */
+ int RESULT_ERROR_UNKNOWN = 1;
+
+ /**
+ * Indicates that call forwarding is not enabled because the recipient is not on a
+ * Fixed Dialing Number (FDN) list.
+ */
+ int RESULT_ERROR_FDN_CHECK_FAILURE = 2;
+
+ /**
+ * Indicates that call forwarding is not supported on the network at this time.
+ */
+ int RESULT_ERROR_NOT_SUPPORTED = 3;
+
+ /**
+ * Call forwarding errors
+ * @hide
+ */
+ @IntDef(prefix = { "RESULT_ERROR_" }, value = {
+ RESULT_ERROR_UNKNOWN,
+ RESULT_ERROR_NOT_SUPPORTED,
+ RESULT_ERROR_FDN_CHECK_FAILURE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface CallForwardingError{
+ }
+ /**
* Called when the call forwarding info is successfully retrieved from the network.
* @param info information about how calls are forwarded
*/
@@ -12964,7 +12998,7 @@
* Called when there was an error retrieving the call forwarding information.
* @param error
*/
- void onError(@CallForwardingInfo.CallForwardingError int error);
+ void onError(@CallForwardingError int error);
}
/**
@@ -13037,9 +13071,9 @@
* @param executor The executor on which the listener will be called. Must be non-null if
* {@code listener} is non-null.
* @param resultListener Asynchronous listener that'll be called when the operation completes.
- * Called with {@link CallForwardingInfo#SUCCESS} if the operation
- * succeeded and an error code from {@link CallForwardingInfo}
- * if it failed.
+ * Called with {@link CallForwardingInfoCallback#RESULT_SUCCESS} if the
+ * operation succeeded and an error code from
+ * {@link CallForwardingInfoCallback} it failed.
*
* @throws IllegalArgumentException if any of the following are true for the parameter
* callForwardingInfo:
@@ -13065,7 +13099,8 @@
@SystemApi
public void setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo,
@Nullable @CallbackExecutor Executor executor,
- @Nullable @CallForwardingInfo.CallForwardingError Consumer<Integer> resultListener) {
+ @Nullable @CallForwardingInfoCallback.CallForwardingError
+ Consumer<Integer> resultListener) {
if (callForwardingInfo == null) {
throw new IllegalArgumentException("callForwardingInfo is null");
}
@@ -13221,7 +13256,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setCallWaitingStatus(boolean enabled, @Nullable Executor executor,
+ public void setCallWaitingEnabled(boolean enabled, @Nullable Executor executor,
@Nullable Consumer<Integer> resultListener) {
if (resultListener != null) {
Objects.requireNonNull(executor);
@@ -13623,4 +13658,38 @@
return true;
}
}
+
+ /**
+ * Returns a list of the equivalent home PLMNs (EF_EHPLMN) from the USIM app.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @return A list of equivalent home PLMNs. Returns an empty list if EF_EHPLMN is empty or
+ * does not exist on the SIM card.
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws SecurityException if the caller doesn't have the permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public @NonNull List<String> getEquivalentHomePlmns() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getEquivalentHomePlmns(getSubId(), mContext.getOpPackageName(),
+ getAttributionTag());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
+
+ return Collections.emptyList();
+ }
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 39859b1..579200e 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -69,6 +69,7 @@
/** {@hide} */
@IntDef(prefix = "HANDOVER_FAILURE_MODE_", value = {
+ HANDOVER_FAILURE_MODE_UNKNOWN,
HANDOVER_FAILURE_MODE_LEGACY,
HANDOVER_FAILURE_MODE_DO_FALLBACK,
HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER,
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
index 7bbe30a..5246470 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
@@ -27,8 +27,11 @@
* See MmTelFeature#Listener for more information.
* {@hide}
*/
-oneway interface IImsMmTelListener {
+ // This interface is not considered oneway because we need to ensure that these operations are
+ // processed by telephony before the control flow returns to the ImsService to perform
+ // operations on the IImsCallSession.
+interface IImsMmTelListener {
void onIncomingCall(IImsCallSession c, in Bundle extras);
void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason);
- void onVoiceMessageCountUpdate(int count);
+ oneway void onVoiceMessageCountUpdate(int count);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index d012703b..e01ea91 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -22,6 +22,7 @@
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
import android.telephony.ims.aidl.IImsRegistrationCallback;
+import com.android.ims.ImsFeatureContainer;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.IIntegerConsumer;
@@ -53,7 +54,6 @@
void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c);
// Internal commands that should not be made public
- void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback,
- boolean oneShot);
+ void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ef5078d..53069a1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -829,8 +829,7 @@
* as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback
* interface.
*/
- void registerMmTelFeatureCallback(int slotId, in IImsServiceFeatureCallback callback,
- boolean oneShot);
+ void registerMmTelFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
/**
* Unregister a callback that was previously registered through
@@ -2221,4 +2220,12 @@
* Whether device can connect to 5G network when two SIMs are active.
*/
boolean canConnectTo5GInDsdsMode();
+
+ /**
+ * Returns a list of the equivalent home PLMNs (EF_EHPLMN) from the USIM app.
+ *
+ * @return A list of equivalent home PLMNs. Returns an empty list if EF_EHPLMN is empty or
+ * does not exist on the SIM card.
+ */
+ List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId);
}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index 0f62c4f..e9227e94 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -107,7 +107,10 @@
fun ParcelFileDescriptor.text() = FileReader(fileDescriptor).readText()
@After
- fun resetIdentity() = uiAutomation.dropShellPermissionIdentity()
+ fun resetChangeIdAndIdentity() {
+ command("am compat reset $TEST_CHANGE_ID $TEST_PKG")
+ uiAutomation.dropShellPermissionIdentity()
+ }
@Test
fun execute() {
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 83fd208..8013bd8 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -130,7 +130,7 @@
when(mTelephonyManager.isSmsCapable()).thenReturn(true);
when(mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)).thenReturn(true);
- when(mRoleManager.getDefaultSmsPackage(anyInt()))
+ when(mRoleManager.getSmsRoleHolder(anyInt()))
.thenReturn(TEST_COMPONENT_NAME.getPackageName());
for (String opStr : APP_OPS_TO_CHECK) {
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 030ddd2..3c3076f 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.fail;
import android.net.LinkProperties.ProvisioningChange;
+import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.system.OsConstants;
import android.util.ArraySet;
@@ -40,7 +41,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 6de31f6..91c9a2a 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.net.util.MacAddressUtils;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.net.module.util.MacAddressUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 71c70da..7497869 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -79,8 +79,8 @@
ISGAME_ATTR = 0x10103f4,
VERSION_ATTR = 0x01010519,
CERT_DIGEST_ATTR = 0x01010548,
- REQUIRED_FEATURE_ATTR = 0x01010557,
- REQUIRED_NOT_FEATURE_ATTR = 0x01010558,
+ REQUIRED_FEATURE_ATTR = 0x01010554,
+ REQUIRED_NOT_FEATURE_ATTR = 0x01010555,
IS_STATIC_ATTR = 0x0101055a,
REQUIRED_SYSTEM_PROPERTY_NAME_ATTR = 0x01010565,
REQUIRED_SYSTEM_PROPERTY_VALUE_ATTR = 0x01010566,
diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
index cf2cb4a..57055f7 100644
--- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
+++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi.p2p.nsd;
parcelable WifiP2pServiceInfo;
diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
index d5a1e8f..e4d28bb 100644
--- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
+++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi.p2p.nsd;
parcelable WifiP2pServiceRequest;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 1c297e7..6928618 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -332,6 +332,7 @@
method public boolean isEasyConnectSupported();
method public boolean isEnhancedOpenSupported();
method public boolean isEnhancedPowerReportingSupported();
+ method public boolean isMultiStaConcurrencySupported();
method public boolean isP2pSupported();
method public boolean isPreferredNetworkOffloadSupported();
method @Deprecated public boolean isScanAlwaysAvailable();
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index 0f71ab4..bf7003c 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -608,10 +608,12 @@
public final class WifiNetworkSuggestion implements android.os.Parcelable {
method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
+ method public boolean isOemPaid();
}
public static final class WifiNetworkSuggestion.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean);
}
public class WifiScanner {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0973d54..fc6c59a 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -29,6 +29,7 @@
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
+import android.net.util.MacAddressUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -40,7 +41,6 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -992,6 +992,16 @@
public boolean trusted;
/**
+ * Indicate whether the network is oem paid or not. Networks are considered oem paid
+ * if the corresponding connection is only available to system apps.
+ *
+ * This bit can only be used by suggestion network, see
+ * {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)}
+ * @hide
+ */
+ public boolean oemPaid;
+
+ /**
* True if this Wifi configuration is created from a {@link WifiNetworkSuggestion},
* false otherwise.
*
@@ -2158,6 +2168,7 @@
ephemeral = false;
osu = false;
trusted = true; // Networks are considered trusted by default.
+ oemPaid = false;
fromWifiNetworkSuggestion = false;
fromWifiNetworkSpecifier = false;
meteredHint = false;
@@ -2278,11 +2289,12 @@
if (this.ephemeral) sbuf.append(" ephemeral");
if (this.osu) sbuf.append(" osu");
if (this.trusted) sbuf.append(" trusted");
+ if (this.oemPaid) sbuf.append(" oemPaid");
if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion");
if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
if (this.meteredHint) sbuf.append(" meteredHint");
if (this.useExternalScores) sbuf.append(" useExternalScores");
- if (this.validatedInternetAccess || this.ephemeral || this.trusted
+ if (this.validatedInternetAccess || this.ephemeral || this.trusted || this.oemPaid
|| this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier
|| this.meteredHint || this.useExternalScores) {
sbuf.append("\n");
@@ -2828,6 +2840,7 @@
ephemeral = source.ephemeral;
osu = source.osu;
trusted = source.trusted;
+ oemPaid = source.oemPaid;
fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion;
fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier;
meteredHint = source.meteredHint;
@@ -2906,6 +2919,7 @@
dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(trusted ? 1 : 0);
+ dest.writeInt(oemPaid ? 1 : 0);
dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0);
dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0);
dest.writeInt(meteredHint ? 1 : 0);
@@ -2981,6 +2995,7 @@
config.isLegacyPasspointConfig = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.trusted = in.readInt() != 0;
+ config.oemPaid = in.readInt() != 0;
config.fromWifiNetworkSuggestion = in.readInt() != 0;
config.fromWifiNetworkSpecifier = in.readInt() != 0;
config.meteredHint = in.readInt() != 0;
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 5388367..fe5002e 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -159,6 +159,11 @@
private boolean mTrusted;
/**
+ * Whether the network is oem paid or not.
+ */
+ private boolean mOemPaid;
+
+ /**
* OSU (Online Sign Up) AP for Passpoint R2.
*/
private boolean mOsuAp;
@@ -358,6 +363,7 @@
mMeteredHint = source.mMeteredHint;
mEphemeral = source.mEphemeral;
mTrusted = source.mTrusted;
+ mTrusted = source.mOemPaid;
mRequestingPackageName =
source.mRequestingPackageName;
mOsuAp = source.mOsuAp;
@@ -722,6 +728,16 @@
}
/** {@hide} */
+ public void setOemPaid(boolean oemPaid) {
+ mOemPaid = oemPaid;
+ }
+
+ /** {@hide} */
+ public boolean isOemPaid() {
+ return mOemPaid;
+ }
+
+ /** {@hide} */
public void setOsuAp(boolean osuAp) {
mOsuAp = osuAp;
}
@@ -958,6 +974,7 @@
dest.writeInt(mMeteredHint ? 1 : 0);
dest.writeInt(mEphemeral ? 1 : 0);
dest.writeInt(mTrusted ? 1 : 0);
+ dest.writeInt(mOemPaid ? 1 : 0);
dest.writeInt(score);
dest.writeLong(txSuccess);
dest.writeDouble(mSuccessfulTxPacketsPerSecond);
@@ -1003,6 +1020,7 @@
info.mMeteredHint = in.readInt() != 0;
info.mEphemeral = in.readInt() != 0;
info.mTrusted = in.readInt() != 0;
+ info.mOemPaid = in.readInt() != 0;
info.score = in.readInt();
info.txSuccess = in.readLong();
info.mSuccessfulTxPacketsPerSecond = in.readDouble();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b4e4210..2ca2d1e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -44,6 +44,7 @@
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
+import android.net.wifi.util.SdkLevelUtil;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -931,6 +932,11 @@
* This can be as a result of adding/updating/deleting a network.
* <br />
* {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
+ * {@link #EXTRA_WIFI_CONFIGURATION} is never set beginning in
+ * {@link android.os.Build.VERSION_CODES#R}.
+ * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
+ * its value is always true beginning in {@link android.os.Build.VERSION_CODES#R}, even if only
+ * a single network changed.
* <br />
* The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
* required to receive this broadcast.
@@ -944,7 +950,8 @@
* The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
* the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
* broadcast is sent.
- * @deprecated this extra is never set. Use {@link #getConfiguredNetworks} to get the full list
+ * @deprecated This extra is never set beginning in {@link android.os.Build.VERSION_CODES#R},
+ * regardless of the target SDK version. Use {@link #getConfiguredNetworks} to get the full list
* of configured networks.
* @hide
*/
@@ -954,7 +961,8 @@
/**
* Multiple network configurations have changed.
* @see #CONFIGURED_NETWORKS_CHANGED_ACTION
- * @deprecated this extra's value is always true.
+ * @deprecated This extra's value is always true beginning in
+ * {@link android.os.Build.VERSION_CODES#R}, regardless of the target SDK version.
* @hide
*/
@Deprecated
@@ -2480,6 +2488,18 @@
}
/**
+ * Query whether the device supports 2 or more concurrent stations (STA) or not.
+ *
+ * @return true if this device supports multiple STA concurrency, false otherwise.
+ */
+ public boolean isMultiStaConcurrencySupported() {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
+ }
+
+ /**
* @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
* with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
* {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
@@ -2512,14 +2532,6 @@
}
/**
- * @return true if this adapter supports multiple simultaneous connections
- * @hide
- */
- public boolean isAdditionalStaSupported() {
- return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
- }
-
- /**
* @return true if this adapter supports Tunnel Directed Link Setup
*/
public boolean isTdlsSupported() {
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index e992c83..9162c5f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -24,7 +24,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.net.MacAddress;
+import android.net.NetworkCapabilities;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.util.SdkLevelUtil;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.TelephonyManager;
@@ -150,6 +152,11 @@
private boolean mIsNetworkUntrusted;
/**
+ * Whether this network will be brought up as OEM paid (OEM_PAID capability bit added).
+ */
+ private boolean mIsNetworkOemPaid;
+
+ /**
* Whether this network will use enhanced MAC randomization.
*/
private boolean mIsEnhancedMacRandomizationEnabled;
@@ -175,6 +182,7 @@
mWapiPskPassphrase = null;
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
+ mIsNetworkOemPaid = false;
mPriorityGroup = 0;
mIsEnhancedMacRandomizationEnabled = false;
}
@@ -543,7 +551,7 @@
/**
* Specifies whether the system will bring up the network (if selected) as untrusted. An
- * untrusted network has its {@link android.net.NetworkCapabilities#NET_CAPABILITY_TRUSTED}
+ * untrusted network has its {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED}
* capability removed. The Wi-Fi network selection process may use this information to
* influence priority of the suggested network for Wi-Fi network selection (most likely to
* reduce it). The connectivity service may use this information to influence the overall
@@ -562,6 +570,41 @@
return this;
}
+ /**
+ * Specifies whether the system will bring up the network (if selected) as OEM paid. An
+ * OEM paid network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} capability
+ * added.
+ * Note:
+ * <li>The connectivity service may use this information to influence the overall
+ * network configuration of the device. This network is typically only available to system
+ * apps.
+ * <li>On devices which support only 1 concurrent connection (indicated via
+ * {@link WifiManager#isMultiStaConcurrencySupported()}, Wi-Fi network selection process may
+ * use this information to influence priority of the suggested network for Wi-Fi network
+ * selection (most likely to reduce it).
+ * <li>On devices which support more than 1 concurrent connections (indicated via
+ * {@link WifiManager#isMultiStaConcurrencySupported()}, these OEM paid networks will be
+ * brought up as a secondary concurrent connection (primary connection will be used
+ * for networks available to the user and all apps.
+ * <p>
+ * <li> An OEM paid network's credentials may not be shared with the user using
+ * {@link #setCredentialSharedWithUser(boolean)}.</li>
+ * <li> If not set, defaults to false (i.e. network is not OEM paid).</li>
+ *
+ * @param isOemPaid Boolean indicating whether the network should be brought up as OEM paid
+ * (if true) or not OEM paid (if false).
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setOemPaid(boolean isOemPaid) {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ mIsNetworkOemPaid = isOemPaid;
+ return this;
+ }
+
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -628,6 +671,7 @@
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.carrierId = mCarrierId;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ wifiConfiguration.oemPaid = mIsNetworkOemPaid;
wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
? WifiConfiguration.RANDOMIZATION_ENHANCED
: WifiConfiguration.RANDOMIZATION_PERSISTENT;
@@ -659,6 +703,7 @@
wifiConfiguration.priority = mPriority;
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ wifiConfiguration.oemPaid = mIsNetworkOemPaid;
mPasspointConfiguration.setCarrierId(mCarrierId);
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
@@ -764,7 +809,15 @@
if (mIsSharedWithUserSet && mIsSharedWithUser) {
throw new IllegalStateException("Should not be both"
+ "setCredentialSharedWithUser and +"
- + "setIsNetworkAsUntrusted to true");
+ + "setUntrusted to true");
+ }
+ mIsSharedWithUser = false;
+ }
+ if (mIsNetworkOemPaid) {
+ if (mIsSharedWithUserSet && mIsSharedWithUser) {
+ throw new IllegalStateException("Should not be both"
+ + "setCredentialSharedWithUser and +"
+ + "setOemPaid to true");
}
mIsSharedWithUser = false;
}
@@ -931,6 +984,7 @@
.append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
.append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+ .append(", isOemPaid=").append(wifiConfiguration.oemPaid)
.append(", priorityGroup=").append(priorityGroup)
.append(" ]");
return sb.toString();
@@ -1026,6 +1080,18 @@
}
/**
+ * @see Builder#setOemPaid(boolean)
+ * @hide
+ */
+ @SystemApi
+ public boolean isOemPaid() {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ return wifiConfiguration.oemPaid;
+ }
+
+ /**
* Get the WifiEnterpriseConfig, or null if unset.
* @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig)
* @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index e2f40cf..dad431c1 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -17,11 +17,10 @@
package android.net.wifi.p2p.nsd;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Build;
import android.text.TextUtils;
-import com.android.net.module.util.DnsSdTxtRecord;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index d4b2051..8af7500 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -33,14 +33,13 @@
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
+import android.net.util.MacAddressUtils;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
-import com.android.net.module.util.MacAddressUtils;
-
import org.junit.Before;
import org.junit.Test;
@@ -68,6 +67,7 @@
WifiConfiguration config = new WifiConfiguration();
config.setPasspointManagementObjectTree(cookie);
config.trusted = false;
+ config.oemPaid = true;
config.updateIdentifier = "1234";
config.fromWifiNetworkSpecifier = true;
config.fromWifiNetworkSuggestion = true;
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 311bbc4..06ae13a 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -61,6 +61,7 @@
writeWifiInfo.txBad = TEST_TX_BAD;
writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
writeWifiInfo.setTrusted(true);
+ writeWifiInfo.setOemPaid(true);
writeWifiInfo.setOsuAp(true);
writeWifiInfo.setFQDN(TEST_FQDN);
writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
@@ -81,6 +82,7 @@
assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
assertTrue(readWifiInfo.isTrusted());
+ assertTrue(readWifiInfo.isOemPaid());
assertTrue(readWifiInfo.isOsuAp());
assertTrue(readWifiInfo.isPasspointAp());
assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index e7f1916c..bda776d 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -33,6 +33,8 @@
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_ADDITIONAL_STA;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_AP_STA;
import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
import static android.net.wifi.WifiManager.WIFI_FEATURE_P2P;
@@ -49,6 +51,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
@@ -83,6 +86,7 @@
import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
import android.net.wifi.WifiManager.TrafficStateCallback;
import android.net.wifi.WifiManager.WifiConnectedNetworkScorer;
+import android.net.wifi.util.SdkLevelUtil;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -1708,6 +1712,34 @@
}
/**
+ * Test behavior of isStaApConcurrencySupported
+ */
+ @Test
+ public void testIsStaApConcurrencyOpenSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WIFI_FEATURE_AP_STA));
+ assertTrue(mWifiManager.isStaApConcurrencySupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WIFI_FEATURE_AP_STA));
+ assertFalse(mWifiManager.isStaApConcurrencySupported());
+ }
+
+ /**
+ * Test behavior of isMultiStaConcurrencySupported
+ */
+ @Test
+ public void testIsMultiStaConcurrencyOpenSupported() throws Exception {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WIFI_FEATURE_ADDITIONAL_STA));
+ assertTrue(mWifiManager.isMultiStaConcurrencySupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WIFI_FEATURE_ADDITIONAL_STA));
+ assertFalse(mWifiManager.isMultiStaConcurrencySupported());
+ }
+
+ /**
* Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
*/
@Test
@@ -1858,7 +1890,6 @@
assertFalse(mWifiManager.isDeviceToDeviceRttSupported());
assertFalse(mWifiManager.isDeviceToApRttSupported());
assertFalse(mWifiManager.isPreferredNetworkOffloadSupported());
- assertFalse(mWifiManager.isAdditionalStaSupported());
assertFalse(mWifiManager.isTdlsSupported());
assertFalse(mWifiManager.isOffChannelTdlsSupported());
assertFalse(mWifiManager.isEnhancedPowerReportingSupported());
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 668d238..6e08ca4 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -22,10 +22,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.net.MacAddress;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.PasspointTestUtils;
+import android.net.wifi.util.SdkLevelUtil;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -192,6 +194,34 @@
/**
* Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for OWE network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForOemPaidEnhancedOpenNetworkWithBssid() {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .setOemPaid(true)
+ .setIsEnhancedOpen(true)
+ .build();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertEquals(TEST_BSSID, suggestion.wifiConfiguration.BSSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.OWE));
+ assertNull(suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.wifiConfiguration.requirePmf);
+ assertTrue(suggestion.wifiConfiguration.oemPaid);
+ assertTrue(suggestion.isOemPaid());
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
* {@link WifiNetworkSuggestion.Builder#build()} for SAE network.
*/
@Test
@@ -1010,6 +1040,41 @@
}
/**
+ * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+ * correct value to the WifiConfiguration.
+ */
+ @Test
+ public void testSetIsNetworkAsOemPaid() {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setOemPaid(true)
+ .build();
+ assertTrue(suggestion.isOemPaid());
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ }
+
+ /**
+ * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+ * correct value to the WifiConfiguration.
+ * Also the {@link WifiNetworkSuggestion#isUserAllowedToManuallyConnect} should be false;
+ */
+ @Test
+ public void testSetIsNetworkAsOemPaidOnPasspointNetwork() {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .setOemPaid(true)
+ .build();
+ assertTrue(suggestion.isOemPaid());
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ }
+
+ /**
* Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
* when set {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)} to true and
* set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
@@ -1027,6 +1092,24 @@
/**
* Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)} to true and
+ * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
+ * together.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetCredentialSharedWithUserWithSetIsNetworkAsOemPaid() {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(true)
+ .setOemPaid(true)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
* when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)}
* and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
* to false on a passpoint suggestion.