Merge "Introduce concept of work types." into sc-dev
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 ed55f00..3bbc945 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -64,7 +64,7 @@
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mImplInstanceManager = new ImplInstanceManager(getContext());
+ mImplInstanceManager = ImplInstanceManager.getInstance(getContext());
}
private class Stub extends IAppSearchManager.Stub {
@@ -102,7 +102,8 @@
}
schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
}
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.setSchema(
packageName,
databaseName,
@@ -133,7 +134,8 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
List<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
for (int i = 0; i < schemas.size(); i++) {
@@ -166,7 +168,8 @@
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
try {
@@ -207,12 +210,18 @@
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
- GenericDocument document = impl.getDocument(packageName, databaseName,
- namespace, uri, typePropertyPaths);
+ GenericDocument document =
+ impl.getDocument(
+ packageName,
+ databaseName,
+ namespace,
+ uri,
+ typePropertyPaths);
resultBuilder.setSuccess(uri, document.getBundle());
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
@@ -245,7 +254,8 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
SearchResultPage searchResultPage =
impl.query(
packageName,
@@ -278,12 +288,14 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
- SearchResultPage searchResultPage = impl.globalQuery(
- queryExpression,
- new SearchSpec(searchSpecBundle),
- packageName,
- callingUid);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ SearchResultPage searchResultPage =
+ impl.globalQuery(
+ queryExpression,
+ new SearchSpec(searchSpecBundle),
+ packageName,
+ callingUid);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -306,7 +318,8 @@
// TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
// opened it
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
invokeCallbackOnResult(
callback,
@@ -324,7 +337,8 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.invalidateNextPageToken(nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -350,15 +364,11 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
- impl.reportUsage(
- packageName,
- databaseName,
- namespace,
- uri,
- usageTimeMillis);
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(/*result=*/ null));
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ impl.reportUsage(packageName, databaseName, namespace, uri, usageTimeMillis);
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
} finally {
@@ -385,7 +395,8 @@
verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
@@ -421,7 +432,8 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.removeByQuery(
packageName,
databaseName,
@@ -441,7 +453,8 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
impl.persistToDisk();
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
@@ -457,7 +470,7 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mImplInstanceManager.getInstance(callingUserId);
+ mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index fe3c2e1..97b1a8c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -41,14 +41,33 @@
public final class ImplInstanceManager {
private static final String APP_SEARCH_DIR = "appSearch";
- private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
+ private static ImplInstanceManager sImplInstanceManager;
- private final Context mContext;
+ private final SparseArray<AppSearchImpl> mInstances = new SparseArray<>();
private final String mGlobalQuerierPackage;
- public ImplInstanceManager(@NonNull Context context) {
- mContext = context;
- mGlobalQuerierPackage = getGlobalAppSearchDataQuerierPackageName(mContext);
+ private ImplInstanceManager(@NonNull String globalQuerierPackage) {
+ mGlobalQuerierPackage = globalQuerierPackage;
+ }
+
+ /**
+ * Gets an instance of ImplInstanceManager to be used.
+ *
+ * <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
+ * existing instance will be returned.
+ */
+ @NonNull
+ public static ImplInstanceManager getInstance(@NonNull Context context) {
+ if (sImplInstanceManager == null) {
+ synchronized (ImplInstanceManager.class) {
+ if (sImplInstanceManager == null) {
+ sImplInstanceManager =
+ new ImplInstanceManager(
+ getGlobalAppSearchDataQuerierPackageName(context));
+ }
+ }
+ }
+ return sImplInstanceManager;
}
/**
@@ -57,30 +76,30 @@
* <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will
* be created.
*
+ * @param context The context
* @param userId The multi-user userId of the device user calling AppSearch
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public AppSearchImpl getInstance(@UserIdInt int userId)
+ public AppSearchImpl getAppSearchImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- AppSearchImpl instance = sInstances.get(userId);
+ AppSearchImpl instance = mInstances.get(userId);
if (instance == null) {
synchronized (ImplInstanceManager.class) {
- instance = sInstances.get(userId);
+ instance = mInstances.get(userId);
if (instance == null) {
- instance = createImpl(userId);
- sInstances.put(userId, instance);
+ instance = createImpl(context, userId);
+ mInstances.put(userId, instance);
}
}
}
return instance;
}
- private AppSearchImpl createImpl(@UserIdInt int userId)
+ private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- File appSearchDir = getAppSearchDir(mContext, userId);
- return AppSearchImpl.create(
- appSearchDir, mContext, userId, mGlobalQuerierPackage);
+ File appSearchDir = getAppSearchDir(context, userId);
+ return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage);
}
private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
@@ -96,7 +115,8 @@
*
* @param context Context of the system service.
*/
- private static String getGlobalAppSearchDataQuerierPackageName(Context context) {
+ @NonNull
+ private static String getGlobalAppSearchDataQuerierPackageName(@NonNull Context context) {
String globalAppSearchDataQuerierPackage =
context.getString(R.string.config_globalAppSearchDataQuerierPackage);
try {
diff --git a/core/api/current.txt b/core/api/current.txt
index ec712d8..3dd1f59 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -46182,6 +46182,7 @@
method @NonNull public android.graphics.Rect getBoundingRectRight();
method @NonNull public android.graphics.Rect getBoundingRectTop();
method @NonNull public java.util.List<android.graphics.Rect> getBoundingRects();
+ method @Nullable public android.graphics.Path getCutoutPath();
method public int getSafeInsetBottom();
method public int getSafeInsetLeft();
method public int getSafeInsetRight();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0f1296e..0a0f77e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7758,11 +7758,13 @@
method public boolean setupInterfaceForSoftApMode(@NonNull String);
method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String);
method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.nl80211.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.PnoScanRequestCallback);
- method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
+ method @Deprecated public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
+ method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>, @Nullable android.os.Bundle);
method public boolean stopPnoScan(@NonNull String);
method public boolean tearDownClientInterface(@NonNull String);
method public boolean tearDownInterfaces();
method public boolean tearDownSoftApInterface(@NonNull String);
+ field public static final String SCANNING_PARAM_ENABLE_6GHZ_RNR = "android.net.wifi.nl80211.SCANNING_PARAM_ENABLE_6GHZ_RNR";
field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c237d7d..ea7dc03 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -684,6 +684,7 @@
method public void holdLock(android.os.IBinder, int);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+ field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 68d3a92..49f508d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5255,6 +5255,7 @@
// We still want a time to be set but gone, such that we can show and hide it
// on demand in case it's a child notification without anything in the header
contentView.setLong(R.id.time, "setTime", mN.when != 0 ? mN.when : mN.creationTime);
+ setTextViewColorSecondary(contentView, R.id.time, p);
}
}
diff --git a/core/java/android/app/people/ConversationChannel.aidl b/core/java/android/app/people/ConversationChannel.aidl
new file mode 100644
index 0000000..78df2f1
--- /dev/null
+++ b/core/java/android/app/people/ConversationChannel.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+parcelable ConversationChannel;
\ No newline at end of file
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
index 0d12ed0..ebe9f60 100644
--- a/core/java/android/app/people/IPeopleManager.aidl
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -17,6 +17,7 @@
package android.app.people;
import android.app.people.ConversationStatus;
+import android.app.people.ConversationChannel;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
import android.os.IBinder;
@@ -26,6 +27,13 @@
* {@hide}
*/
interface IPeopleManager {
+
+ /**
+ * Returns the specified conversation from the conversations list. If the conversation can't be
+ * found, returns null.
+ */
+ ConversationChannel getConversation(in String packageName, int userId, in String shortcutId);
+
/**
* Returns the recent conversations. The conversations that have customized notification
* settings are excluded from the returned list.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 68792b2..9ae9c25 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3385,6 +3385,7 @@
* {@link #hasSystemFeature}: This device supports HDMI-CEC.
* @hide
*/
+ @TestApi
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index fe8bf9d..e6c0f6a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6265,6 +6265,55 @@
}
/**
+ * Returns whether this {@code SigningDetails} has a signer in common with the provided
+ * {@code otherDetails} with the specified {@code flags} capabilities provided by this
+ * signer.
+ *
+ * <p>Note this method allows for the signing lineage to diverge, so this should only be
+ * used for instances where the only requirement is a common signer in the lineage with
+ * the specified capabilities. If the current signer of this instance is an ancestor of
+ * {@code otherDetails} then {@code true} is immediately returned since the current signer
+ * has all capabilities granted.
+ */
+ public boolean hasCommonSignerWithCapability(SigningDetails otherDetails,
+ @CertCapabilities int flags) {
+ if (this == UNKNOWN || otherDetails == UNKNOWN) {
+ return false;
+ }
+ // If either is signed with more than one signer then both must be signed by the same
+ // signers to consider the capabilities granted.
+ if (signatures.length > 1 || otherDetails.signatures.length > 1) {
+ return signaturesMatchExactly(otherDetails);
+ }
+ // The Signature class does not use the granted capabilities in the hashCode
+ // computation, so a Set can be used to check for a common signer.
+ Set<Signature> otherSignatures = new ArraySet<>();
+ if (otherDetails.hasPastSigningCertificates()) {
+ otherSignatures.addAll(Arrays.asList(otherDetails.pastSigningCertificates));
+ } else {
+ otherSignatures.addAll(Arrays.asList(otherDetails.signatures));
+ }
+ // If the current signer of this instance is an ancestor of the other than return true
+ // since all capabilities are granted to the current signer.
+ if (otherSignatures.contains(signatures[0])) {
+ return true;
+ }
+ if (hasPastSigningCertificates()) {
+ // Since the current signer was checked above and the last signature in the
+ // pastSigningCertificates is the current signer skip checking the last element.
+ for (int i = 0; i < pastSigningCertificates.length - 1; i++) {
+ if (otherSignatures.contains(pastSigningCertificates[i])) {
+ // If the caller specified multiple capabilities ensure all are set.
+ if ((pastSigningCertificates[i].getFlags() & flags) == flags) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Determines if the provided {@code oldDetails} is an ancestor of this one, and whether or
* not this one grants it the provided capability, represented by the {@code flags}
* parameter. In the event of signing certificate rotation, a package may still interact
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 75893d9..588bc01 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -301,7 +301,8 @@
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
- enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, null /* surface */);
+ enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, null /* surface */,
+ false /* debugConsent */);
}
/**
@@ -313,18 +314,20 @@
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
*
- * @param token a unique token provided by a recent creation or verification of device
- * credentials (e.g. pin, pattern or password).
- * @param cancel an object that can be used to cancel enrollment
- * @param userId the user to whom this face will belong to
- * @param callback an object to receive enrollment events
- * @param surface optional camera preview surface for a single-camera device. Must be null if
- * not used.
+ * @param hardwareAuthToken a unique token provided by a recent creation or
+ * verification of device credentials (e.g. pin, pattern or password).
+ * @param cancel an object that can be used to cancel enrollment
+ * @param userId the user to whom this face will belong to
+ * @param callback an object to receive enrollment events
+ * @param surface optional camera preview surface for a single-camera device.
+ * Must be null if not used.
+ * @param debugConsent a feature flag that the user has consented to debug.
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
- EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface) {
+ EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface,
+ boolean debugConsent) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
@@ -343,7 +346,7 @@
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enroll");
mService.enroll(userId, mToken, hardwareAuthToken, mServiceReceiver,
- mContext.getOpPackageName(), disabledFeatures, surface);
+ mContext.getOpPackageName(), disabledFeatures, surface, debugConsent);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 1b188e8..a3e7e2d 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -74,7 +74,7 @@
// Start face enrollment
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
- String opPackageName, in int [] disabledFeatures, in Surface surface);
+ String opPackageName, in int [] disabledFeatures, in Surface surface, boolean debugConsent);
// Start remote face enrollment
void enrollRemotely(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 9fdc72b..59292baa 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -36,7 +36,6 @@
import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.content.pm.IDataLoaderStatusListener;
-import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.InstallationFileParcel;
import android.text.TextUtils;
@@ -71,8 +70,7 @@
@Nullable StorageHealthCheckParams healthCheckParams,
@Nullable IStorageHealthListener healthListener,
@NonNull List<InstallationFileParcel> addedFiles,
- @NonNull PerUidReadTimeouts[] perUidReadTimeouts,
- IPackageLoadingProgressCallback progressCallback) throws IOException {
+ @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException {
// TODO(b/136132412): validity check if session should not be incremental
IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
Context.INCREMENTAL_SERVICE);
@@ -97,11 +95,7 @@
throw new IOException("Unknown file location: " + file.location);
}
}
- // Register progress loading callback after files have been added
- if (progressCallback != null) {
- incrementalManager.registerLoadingProgressCallback(stageDir.getAbsolutePath(),
- progressCallback);
- }
+
result.startLoading();
return result;
@@ -186,7 +180,6 @@
try {
mDefaultStorage.unBind(mStageDir.getAbsolutePath());
- mDefaultStorage.unregisterLoadingProgressListener();
} catch (IOException ignored) {
}
mDefaultStorage = null;
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index b1b2925..8b6082b3 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -28,7 +28,10 @@
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.app.AppOpsManager.opToPermission;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
+import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.ComponentName;
@@ -41,12 +44,14 @@
import android.content.pm.ResolveInfo;
import android.icu.text.ListFormatter;
import android.location.LocationManager;
+import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.speech.RecognitionService;
import android.speech.RecognizerIntent;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
@@ -75,6 +80,9 @@
private static final String PROPERTY_LOCATION_INDICATORS_ENABLED =
"location_indicators_enabled";
+ /** Whether to show the Permissions Hub. */
+ private static final String PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled";
+
/** How long after an access to show it as "recent" */
private static final String RECENT_ACCESS_TIME_MS = "recent_acccess_time_ms";
@@ -84,17 +92,25 @@
/** The name of the expected voice IME subtype */
private static final String VOICE_IME_SUBTYPE = "voice";
+ private static final String SYSTEM_PKG = "android";
+
private static final long DEFAULT_RUNNING_TIME_MS = 5000L;
private static final long DEFAULT_RECENT_TIME_MS = 30000L;
+ private static boolean shouldShowPermissionsHub() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_PERMISSIONS_HUB_2_ENABLED, false);
+ }
+
private static boolean shouldShowIndicators() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_CAMERA_MIC_ICONS_ENABLED, true);
+ PROPERTY_CAMERA_MIC_ICONS_ENABLED, true) || shouldShowPermissionsHub();
}
private static boolean shouldShowLocationIndicator() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_INDICATORS_ENABLED, false);
+ PROPERTY_LOCATION_INDICATORS_ENABLED, false)
+ || shouldShowPermissionsHub();
}
private static long getRecentThreshold(Long now) {
@@ -113,7 +129,7 @@
);
private static final List<String> MIC_OPS = List.of(
- OPSTR_PHONE_CALL_CAMERA,
+ OPSTR_PHONE_CALL_MICROPHONE,
OPSTR_RECORD_AUDIO
);
@@ -163,6 +179,13 @@
return mUserContexts.get(user);
}
+ // TODO ntmyren: Replace this with better check if this moves beyond teamfood
+ private boolean isAppPredictor(String packageName, UserHandle user) {
+ return shouldShowPermissionsHub() && getUserContext(user).getPackageManager()
+ .checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
* @see PermissionManager.getIndicatorAppOpUsageData
*/
@@ -186,7 +209,28 @@
Map<PackageAttribution, CharSequence> packagesWithAttributionLabels =
getTrustedAttributions(rawUsages.get(MICROPHONE), proxyChains);
- List<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
+ ArrayList<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
+
+ // If we have a phone call, and a carrier privileged app using microphone, hide the
+ // phone call.
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ boolean hasPhoneCall = usedPermGroups.contains(OPSTR_PHONE_CALL_CAMERA)
+ || usedPermGroups.contains(OPSTR_PHONE_CALL_MICROPHONE);
+ if (hasPhoneCall && usedPermGroups.contains(MICROPHONE) && audioManager.getMode()
+ == MODE_IN_COMMUNICATION) {
+ TelephonyManager telephonyManager =
+ mContext.getSystemService(TelephonyManager.class);
+ List<OpUsage> permUsages = rawUsages.get(MICROPHONE);
+ for (int usageNum = 0; usageNum < permUsages.size(); usageNum++) {
+ if (telephonyManager.checkCarrierPrivilegesForPackage(
+ permUsages.get(usageNum).packageName)
+ == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ usedPermGroups.remove(OPSTR_PHONE_CALL_CAMERA);
+ usedPermGroups.remove(OPSTR_PHONE_CALL_MICROPHONE);
+ }
+ }
+ }
+
for (int permGroupNum = 0; permGroupNum < usedPermGroups.size(); permGroupNum++) {
boolean isPhone = false;
String permGroup = usedPermGroups.get(permGroupNum);
@@ -269,8 +313,11 @@
if (lastAccessTime < recentThreshold && !attrOpEntry.isRunning()) {
continue;
}
- if (!isUserSensitive(packageName, user, op)
- && !isLocationProvider(packageName, user)) {
+
+ if (packageName.equals(SYSTEM_PKG)
+ || (!isUserSensitive(packageName, user, op)
+ && !isLocationProvider(packageName, user)
+ && !isAppPredictor(packageName, user))) {
continue;
}
diff --git a/core/java/android/rotationresolver/OWNERS b/core/java/android/rotationresolver/OWNERS
index 81b6f05..733fca9 100644
--- a/core/java/android/rotationresolver/OWNERS
+++ b/core/java/android/rotationresolver/OWNERS
@@ -1 +1 @@
-include /core/java/android/rotationresolver/OWNERS
+include /core/java/android/service/rotationresolver/OWNERS
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index a44ed59..698cb77 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -21,7 +21,9 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import android.annotation.Dimension;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.view.Surface.Rotation;
/**
@@ -69,4 +71,34 @@
}
return rotated;
}
+
+ /**
+ * Sets a matrix such that given a rotation, it transforms physical display
+ * coordinates to that rotation's logical coordinates.
+ *
+ * @param rotation the rotation to which the matrix should transform
+ * @param out the matrix to be set
+ */
+ public static void transformPhysicalToLogicalCoordinates(@Rotation int rotation,
+ @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
+ switch (rotation) {
+ case ROTATION_0:
+ out.reset();
+ break;
+ case ROTATION_90:
+ out.setRotate(270);
+ out.postTranslate(0, physicalWidth);
+ break;
+ case ROTATION_180:
+ out.setRotate(180);
+ out.postTranslate(physicalWidth, physicalHeight);
+ break;
+ case ROTATION_270:
+ out.setRotate(90);
+ out.postTranslate(physicalHeight, 0);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown rotation: " + rotation);
+ }
+ }
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 525ac53..e1a4402 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -23,6 +23,7 @@
import static android.view.DisplayCutoutProto.BOUND_RIGHT;
import static android.view.DisplayCutoutProto.BOUND_TOP;
import static android.view.DisplayCutoutProto.INSETS;
+import static android.view.Surface.ROTATION_0;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -31,13 +32,16 @@
import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Pair;
+import android.util.RotationUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface.Rotation;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -69,6 +73,9 @@
"com.android.internal.display_cutout_emulation";
private static final Rect ZERO_RECT = new Rect();
+ private static final CutoutPathParserInfo EMPTY_PARSER_INFO = new CutoutPathParserInfo(
+ 0 /* displayWidth */, 0 /* displayHeight */, 0f /* density */, "" /* cutoutSpec */,
+ 0 /* rotation */, 0f /* scale */);
/**
* An instance where {@link #isEmpty()} returns {@code true}.
@@ -76,7 +83,7 @@
* @hide
*/
public static final DisplayCutout NO_CUTOUT = new DisplayCutout(
- ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT,
+ ZERO_RECT, Insets.NONE, ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT, EMPTY_PARSER_INFO,
false /* copyArguments */);
@@ -96,11 +103,15 @@
@GuardedBy("CACHE_LOCK")
private static Insets sCachedWaterfallInsets;
+ @GuardedBy("CACHE_LOCK")
+ private static CutoutPathParserInfo sCachedCutoutPathParserInfo;
+ @GuardedBy("CACHE_LOCK")
+ private static Path sCachedCutoutPath;
+
private final Rect mSafeInsets;
@NonNull
private final Insets mWaterfallInsets;
-
/**
* The bound is at the left of the screen.
* @hide
@@ -210,6 +221,7 @@
}
return result;
}
+
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
@@ -232,6 +244,106 @@
private final Bounds mBounds;
/**
+ * Stores all the needed info to create the cutout paths.
+ *
+ * @hide
+ */
+ public static class CutoutPathParserInfo {
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
+ private final float mDensity;
+ private final String mCutoutSpec;
+ private final @Rotation int mRotation;
+ private final float mScale;
+
+ public CutoutPathParserInfo(int displayWidth, int displayHeight, float density,
+ String cutoutSpec, @Rotation int rotation, float scale) {
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mDensity = density;
+ mCutoutSpec = cutoutSpec == null ? "" : cutoutSpec;
+ mRotation = rotation;
+ mScale = scale;
+ }
+
+ public CutoutPathParserInfo(CutoutPathParserInfo cutoutPathParserInfo) {
+ mDisplayWidth = cutoutPathParserInfo.mDisplayWidth;
+ mDisplayHeight = cutoutPathParserInfo.mDisplayHeight;
+ mDensity = cutoutPathParserInfo.mDensity;
+ mCutoutSpec = cutoutPathParserInfo.mCutoutSpec;
+ mRotation = cutoutPathParserInfo.mRotation;
+ mScale = cutoutPathParserInfo.mScale;
+ }
+
+ public int getDisplayWidth() {
+ return mDisplayWidth;
+ }
+
+ public int getDisplayHeight() {
+ return mDisplayHeight;
+ }
+
+ public float getDensity() {
+ return mDensity;
+ }
+
+ public @NonNull String getCutoutSpec() {
+ return mCutoutSpec;
+ }
+
+ public int getRotation() {
+ return mRotation;
+ }
+
+ public float getScale() {
+ return mScale;
+ }
+
+ private boolean hasCutout() {
+ return !mCutoutSpec.isEmpty();
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ result = result * 48271 + Integer.hashCode(mDisplayWidth);
+ result = result * 48271 + Integer.hashCode(mDisplayHeight);
+ result = result * 48271 + Float.hashCode(mDensity);
+ result = result * 48271 + mCutoutSpec.hashCode();
+ result = result * 48271 + Integer.hashCode(mRotation);
+ result = result * 48271 + Float.hashCode(mScale);
+ return result;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof CutoutPathParserInfo) {
+ CutoutPathParserInfo c = (CutoutPathParserInfo) o;
+ return mDisplayWidth == c.mDisplayWidth && mDisplayHeight == c.mDisplayHeight
+ && mDensity == c.mDensity && mCutoutSpec.equals(c.mCutoutSpec)
+ && mRotation == c.mRotation && mScale == c.mScale;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "CutoutPathParserInfo{displayWidth=" + mDisplayWidth
+ + " displayHeight=" + mDisplayHeight
+ + " density={" + mDensity + "}"
+ + " cutoutSpec={" + mCutoutSpec + "}"
+ + " rotation={" + mRotation + "}"
+ + " scale={" + mScale + "}"
+ + "}";
+ }
+ }
+
+ private final @NonNull CutoutPathParserInfo mCutoutPathParserInfo;
+
+ /**
* Creates a DisplayCutout instance.
*
* <p>Note that this is only useful for tests. For production code, developers should always
@@ -251,7 +363,8 @@
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
- this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, true);
+ this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, null,
+ true);
}
/**
@@ -276,7 +389,7 @@
@Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom,
@NonNull Insets waterfallInsets) {
this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
- true);
+ null, true);
}
/**
@@ -294,7 +407,7 @@
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
- this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects),
+ this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects), null,
true /* copyArguments */);
}
@@ -303,28 +416,42 @@
*
* @param safeInsets the insets from each edge which avoid the display cutout as returned by
* {@link #getSafeInsetTop()} etc.
+ * @param waterfallInsets the insets for the curved areas in waterfall display.
+ * @param boundLeft the left bounding rect of the display cutout in pixels. If null is passed,
+ * it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundTop the top bounding rect of the display cutout in pixels. If null is passed,
+ * it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundRight the right bounding rect of the display cutout in pixels. If null is
+ * passed, it's treated as an empty rectangle (0,0)-(0,0).
+ * @param boundBottom the bottom bounding rect of the display cutout in pixels. If null is
+ * passed, it's treated as an empty rectangle (0,0)-(0,0).
+ * @param info the cutout path parser info.
* @param copyArguments if true, create a copy of the arguments. If false, the passed arguments
* are not copied and MUST remain unchanged forever.
*/
- private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft,
- Rect boundTop, Rect boundRight, Rect boundBottom, boolean copyArguments) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft, Rect boundTop,
+ Rect boundRight, Rect boundBottom, CutoutPathParserInfo info,
+ boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments);
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect[] bounds,
- boolean copyArguments) {
+ CutoutPathParserInfo info, boolean copyArguments) {
mSafeInsets = getCopyOrRef(safeInsets, copyArguments);
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = new Bounds(bounds, copyArguments);
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
- private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds) {
+ private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds,
+ CutoutPathParserInfo info) {
mSafeInsets = safeInsets;
mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets;
mBounds = bounds;
-
+ mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info;
}
private static Rect getCopyOrRef(Rect r, boolean copyArguments) {
@@ -534,10 +661,70 @@
return mBounds.getRect(BOUNDS_POSITION_BOTTOM);
}
+ /**
+ * Returns a {@link Path} that contains the cutout paths of all sides on the display.
+ *
+ * To get a cutout path for one specific side, apps can intersect the {@link Path} with the
+ * {@link Rect} obtained from {@link #getBoundingRectLeft()}, {@link #getBoundingRectTop()},
+ * {@link #getBoundingRectRight()} or {@link #getBoundingRectBottom()}.
+ *
+ * @return a {@link Path} contains all the cutout paths based on display coordinate. Returns
+ * null if there is no cutout on the display.
+ */
+ public @Nullable Path getCutoutPath() {
+ if (!mCutoutPathParserInfo.hasCutout()) {
+ return null;
+ }
+ synchronized (CACHE_LOCK) {
+ if (mCutoutPathParserInfo.equals(sCachedCutoutPathParserInfo)) {
+ return sCachedCutoutPath;
+ }
+ }
+ final CutoutSpecification cutoutSpec = new CutoutSpecification.Parser(
+ mCutoutPathParserInfo.getDensity(), mCutoutPathParserInfo.getDisplayWidth(),
+ mCutoutPathParserInfo.getDisplayHeight())
+ .parse(mCutoutPathParserInfo.getCutoutSpec());
+
+ final Path cutoutPath = cutoutSpec.getPath();
+ if (cutoutPath == null || cutoutPath.isEmpty()) {
+ return null;
+ }
+ final Matrix matrix = new Matrix();
+ if (mCutoutPathParserInfo.getRotation() != ROTATION_0) {
+ RotationUtils.transformPhysicalToLogicalCoordinates(
+ mCutoutPathParserInfo.getRotation(),
+ mCutoutPathParserInfo.getDisplayWidth(),
+ mCutoutPathParserInfo.getDisplayHeight(),
+ matrix
+ );
+ }
+ matrix.postScale(mCutoutPathParserInfo.getScale(), mCutoutPathParserInfo.getScale());
+ cutoutPath.transform(matrix);
+
+ synchronized (CACHE_LOCK) {
+ sCachedCutoutPathParserInfo = new CutoutPathParserInfo(mCutoutPathParserInfo);
+ sCachedCutoutPath = cutoutPath;
+ }
+ return cutoutPath;
+ }
+
+ /**
+ * @return the {@link CutoutPathParserInfo};
+ *
+ * @hide
+ */
+ public CutoutPathParserInfo getCutoutPathParserInfo() {
+ return mCutoutPathParserInfo;
+ }
+
@Override
public int hashCode() {
- return (mSafeInsets.hashCode() * 48271 + mBounds.hashCode()) * 48271
- + mWaterfallInsets.hashCode();
+ int result = 0;
+ result = 48271 * result + mSafeInsets.hashCode();
+ result = 48271 * result + mBounds.hashCode();
+ result = 48271 * result + mWaterfallInsets.hashCode();
+ result = 48271 * result + mCutoutPathParserInfo.hashCode();
+ return result;
}
@Override
@@ -548,7 +735,8 @@
if (o instanceof DisplayCutout) {
DisplayCutout c = (DisplayCutout) o;
return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds)
- && mWaterfallInsets.equals(c.mWaterfallInsets);
+ && mWaterfallInsets.equals(c.mWaterfallInsets)
+ && mCutoutPathParserInfo.equals(c.mCutoutPathParserInfo);
}
return false;
}
@@ -558,6 +746,7 @@
return "DisplayCutout{insets=" + mSafeInsets
+ " waterfall=" + mWaterfallInsets
+ " boundingRect={" + mBounds + "}"
+ + " cutoutPathParserInfo={" + mCutoutPathParserInfo + "}"
+ "}";
}
@@ -607,7 +796,7 @@
}
return new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds,
- false /* copyArguments */);
+ mCutoutPathParserInfo, false /* copyArguments */);
}
private Rect insetInsets(int insetLeft, int insetTop, int insetRight, int insetBottom,
@@ -638,7 +827,8 @@
* @hide
*/
public DisplayCutout replaceSafeInsets(Rect safeInsets) {
- return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds);
+ return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds,
+ mCutoutPathParserInfo);
}
private static int atLeastZero(int value) {
@@ -658,16 +848,18 @@
for (int i = 0; i < BOUNDS_POSITION_LENGTH; ++i) {
bounds[i] = (pos == i) ? new Rect(left, top, right, bottom) : new Rect();
}
- return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null, false /* copyArguments */);
}
/**
- * Creates an instance from a bounding and waterfall insets.
+ * Creates an instance from bounds, waterfall insets and CutoutPathParserInfo.
*
* @hide
*/
- public static DisplayCutout fromBoundsAndWaterfall(Rect[] bounds, Insets waterfallInsets) {
- return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, false /* copyArguments */);
+ public static DisplayCutout constructDisplayCutout(Rect[] bounds, Insets waterfallInsets,
+ CutoutPathParserInfo info) {
+ return new DisplayCutout(ZERO_RECT, waterfallInsets, bounds, info,
+ false /* copyArguments */);
}
/**
@@ -676,7 +868,8 @@
* @hide
*/
public static DisplayCutout fromBounds(Rect[] bounds) {
- return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, false /* copyArguments */);
+ return new DisplayCutout(ZERO_RECT, Insets.NONE, bounds, null /* cutoutPathParserInfo */,
+ false /* copyArguments */);
}
/**
@@ -686,10 +879,12 @@
*
* @hide
*/
- public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
- return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
+ public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
+ int displayHeight) {
+ return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+ res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
- loadWaterfallInset(res));
+ loadWaterfallInset(res)).second;
}
/**
@@ -699,7 +894,7 @@
*/
public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
return pathAndDisplayCutoutFromSpec(
- res.getString(R.string.config_mainBuiltInDisplayCutout),
+ res.getString(R.string.config_mainBuiltInDisplayCutout), null,
displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
loadWaterfallInset(res)).first;
}
@@ -710,14 +905,30 @@
* @hide
*/
@VisibleForTesting(visibility = PRIVATE)
- public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
- float density, Insets waterfallInsets) {
+ public static DisplayCutout fromSpec(String pathSpec, int displayWidth,
+ int displayHeight, float density, Insets waterfallInsets) {
return pathAndDisplayCutoutFromSpec(
- spec, displayWidth, displayHeight, density, waterfallInsets).second;
+ pathSpec, null, displayWidth, displayHeight, density, waterfallInsets)
+ .second;
}
- private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(String spec,
- int displayWidth, int displayHeight, float density, Insets waterfallInsets) {
+ /**
+ * Gets the cutout path and the corresponding DisplayCutout instance from the spec string.
+ *
+ * @param pathSpec the spec string read from config_mainBuiltInDisplayCutout.
+ * @param rectSpec the spec string read from config_mainBuiltInDisplayCutoutRectApproximation.
+ * @param displayWidth the display width.
+ * @param displayHeight the display height.
+ * @param density the display density.
+ * @param waterfallInsets the waterfall insets of the display.
+ * @return a Pair contains the cutout path and the corresponding DisplayCutout instance.
+ */
+ private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec(
+ String pathSpec, String rectSpec, int displayWidth, int displayHeight, float density,
+ Insets waterfallInsets) {
+ // Always use the rect approximation spec to create the cutout if it's not null because
+ // transforming and sending a Region constructed from a path is very costly.
+ String spec = rectSpec != null ? rectSpec : pathSpec;
if (TextUtils.isEmpty(spec) && waterfallInsets.equals(Insets.NONE)) {
return NULL_PAIR;
}
@@ -750,9 +961,12 @@
Math.max(waterfallInsets.bottom, safeInset.bottom));
}
+ final CutoutPathParserInfo cutoutPathParserInfo = new CutoutPathParserInfo(displayWidth,
+ displayHeight, density, pathSpec.trim(), ROTATION_0, 1f /* scale */);
+
final DisplayCutout cutout = new DisplayCutout(
- safeInset, waterfallInsets, boundLeft, boundTop,
- boundRight, boundBottom, false /* copyArguments */);
+ safeInset, waterfallInsets, boundLeft, boundTop, boundRight, boundBottom,
+ cutoutPathParserInfo , false /* copyArguments */);
final Pair<Path, DisplayCutout> result = new Pair<>(cutoutSpec.getPath(), cutout);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
@@ -817,6 +1031,12 @@
out.writeTypedObject(cutout.mSafeInsets, flags);
out.writeTypedArray(cutout.mBounds.getRects(), flags);
out.writeTypedObject(cutout.mWaterfallInsets, flags);
+ out.writeInt(cutout.mCutoutPathParserInfo.getDisplayWidth());
+ out.writeInt(cutout.mCutoutPathParserInfo.getDisplayHeight());
+ out.writeFloat(cutout.mCutoutPathParserInfo.getDensity());
+ out.writeString(cutout.mCutoutPathParserInfo.getCutoutSpec());
+ out.writeInt(cutout.mCutoutPathParserInfo.getRotation());
+ out.writeFloat(cutout.mCutoutPathParserInfo.getScale());
}
}
@@ -860,9 +1080,17 @@
Rect[] bounds = new Rect[BOUNDS_POSITION_LENGTH];
in.readTypedArray(bounds, Rect.CREATOR);
Insets waterfallInsets = in.readTypedObject(Insets.CREATOR);
+ int displayWidth = in.readInt();
+ int displayHeight = in.readInt();
+ float density = in.readFloat();
+ String cutoutSpec = in.readString();
+ int rotation = in.readInt();
+ float scale = in.readFloat();
+ final CutoutPathParserInfo info = new CutoutPathParserInfo(
+ displayWidth, displayHeight, density, cutoutSpec, rotation, scale);
return new DisplayCutout(
- safeInsets, waterfallInsets, bounds, false /* copyArguments */);
+ safeInsets, waterfallInsets, bounds, info, false /* copyArguments */);
}
public DisplayCutout get() {
@@ -884,7 +1112,15 @@
bounds.scale(scale);
final Rect waterfallInsets = mInner.mWaterfallInsets.toRect();
waterfallInsets.scale(scale);
- mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds);
+ final CutoutPathParserInfo info = new CutoutPathParserInfo(
+ mInner.mCutoutPathParserInfo.getDisplayWidth(),
+ mInner.mCutoutPathParserInfo.getDisplayHeight(),
+ mInner.mCutoutPathParserInfo.getDensity(),
+ mInner.mCutoutPathParserInfo.getCutoutSpec(),
+ mInner.mCutoutPathParserInfo.getRotation(),
+ scale);
+
+ mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds, info);
}
@Override
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 106e392..0a1a231 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -414,6 +414,15 @@
*/
public static final int SECURE = 0x00000080;
+
+ /**
+ * Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is
+ * set. This blocks the client until all the buffers have been presented. If the buffers
+ * have presentation timestamps, then we may drop buffers.
+ * @hide
+ */
+ public static final int ENABLE_BACKPRESSURE = 0x00000100;
+
/**
* Surface creation flag: Creates a surface where color components are interpreted
* as "non pre-multiplied" by their alpha channel. Of course this flag is
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0e878fc..4ef63ae 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -262,7 +262,7 @@
}
}
- binder::Status onScreenCaptureComplete(
+ binder::Status onScreenCaptureCompleted(
const gui::ScreenCaptureResults& captureResults) override {
JNIEnv* env = getenv();
if (captureResults.result != NO_ERROR || captureResults.buffer == nullptr) {
@@ -270,6 +270,7 @@
gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
return binder::Status::ok();
}
+ captureResults.fence->waitForever("");
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, captureResults.buffer->toAHardwareBuffer());
const jint namedColorSpace =
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 396f954..4a0a35d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2697,11 +2697,11 @@
The app can check whether it has this authorization by calling
{@link android.provider.Settings#canDrawOverlays
Settings.canDrawOverlays()}.
- <p>Protection level: signature|appop|preinstalled|pre23|development -->
+ <p>Protection level: signature|appop|installer|recents|appPredictor|pre23|development -->
<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
android:label="@string/permlab_systemAlertWindow"
android:description="@string/permdesc_systemAlertWindow"
- android:protectionLevel="signature|appop|preinstalled|pre23|development" />
+ android:protectionLevel="signature|appop|installer|recents|appPredictor|pre23|development" />
<!-- @SystemApi @hide Allows an application to create windows using the type
{@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 8940776..4f920da 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -240,34 +240,34 @@
<color name="system_main_0">#ffffff</color>
<!-- Shade of the main system color at 95% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_50">#ebf1f8</color>
+ <color name="system_main_50">#f0f0f0</color>
<!-- Shade of the main system color at 90% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_100">#dde3ea</color>
+ <color name="system_main_100">#e2e2e2</color>
<!-- Shade of the main system color at 80% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_200">#c1c7cd</color>
+ <color name="system_main_200">#c6c6c6</color>
<!-- Shade of the main system color at 70% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_300">#a6acb2</color>
+ <color name="system_main_300">#ababab</color>
<!-- Shade of the main system color at 60% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_400">#8b9197</color>
+ <color name="system_main_400">#909090</color>
<!-- Shade of the main system color at 50% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_500">#72787d</color>
+ <color name="system_main_500">#777777</color>
<!-- Shade of the main system color at 40% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_600">#595f64</color>
+ <color name="system_main_600">#5e5e5e</color>
<!-- Shade of the main system color at 30% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_700">#42474d</color>
+ <color name="system_main_700">#464646</color>
<!-- Shade of the main system color at 20% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_800">#2c3136</color>
+ <color name="system_main_800">#303030</color>
<!-- Shade of the main system color at 10% lightness.
This value can be overlaid at runtime by OverlayManager RROs. -->
- <color name="system_main_900">#171c21</color>
+ <color name="system_main_900">#1b1b1b</color>
<!-- Darkest shade of the main color used by the system. Black.
This value can be overlaid at runtime by OverlayManager RROs. -->
<color name="system_main_1000">#000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 71b59e4..5e0cda6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4632,6 +4632,10 @@
maximum screen area that can be occupied by the app in the letterbox mode. -->
<item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item>
+ <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and
+ corners of the activity won't be rounded. -->
+ <integer name="config_letterboxActivityCornersRadius">0</integer>
+
<!-- If true, hide the display cutout with display area -->
<bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 78a6e62..dfccdf4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4132,6 +4132,7 @@
<java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
<java-symbol type="dimen" name="config_taskLetterboxAspectRatio" />
+ <java-symbol type="integer" name="config_letterboxActivityCornersRadius" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
diff --git a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
index 24f45a5..bffd1e4 100644
--- a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
+++ b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
@@ -28,6 +28,7 @@
import static org.junit.Assert.fail;
import android.content.pm.PackageParser.SigningDetails;
+import android.util.ArraySet;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -35,6 +36,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SigningDetailsTest {
@@ -208,8 +211,8 @@
SigningDetails result1 = noLineageDetails.mergeLineageWith(lineageDetails);
SigningDetails result2 = lineageDetails.mergeLineageWith(noLineageDetails);
- assertTrue(result1 == lineageDetails);
- assertTrue(result2 == lineageDetails);
+ assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE);
+ assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE);
}
@Test
@@ -271,8 +274,10 @@
SigningDetails result1 = singleSignerDetails.mergeLineageWith(fullLineageDetails);
SigningDetails result2 = fullLineageDetails.mergeLineageWith(singleSignerDetails);
- assertTrue(result1 == fullLineageDetails);
- assertTrue(result2 == fullLineageDetails);
+ assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE,
+ THIRD_SIGNATURE);
+ assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE,
+ THIRD_SIGNATURE);
}
@Test
@@ -605,6 +610,213 @@
assertTrue(secondLineageDetails.hasCommonAncestor(firstLineageDetails));
}
+ @Test
+ public void hasCommonSignerWithCapabilities_singleMatchingSigner_returnsTrue()
+ throws Exception {
+ // The hasCommonSignerWithCapabilities method is intended to grant the specified
+ // capabilities to a requesting package that has a common signer in the lineage (or as the
+ // current signer) even if their signing identities have diverged. This test verifies if the
+ // two SigningDetails have the same single signer then the requested capability can be
+ // granted since the current signer always has all capabilities granted.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE);
+ SigningDetails secondSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertTrue(firstDetails.hasCommonSignerWithCapability(secondSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleDifferentSigners_returnsFalse()
+ throws Exception {
+ // If each package is signed by a single different signer then the method should return
+ // false since there is no shared signer.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_oneWithMultipleSigners_returnsFalse()
+ throws Exception {
+ // If one of the packages is signed with multiple signers and the other only a single signer
+ // this method should return false since all signers must match exactly for multiple signer
+ // cases.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_multipleMatchingSigners_returnsTrue()
+ throws Exception {
+ // if both packages are signed by the same multiple signers then this method should return
+ // true since the current signer is granted all capabilities.
+ SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE, FIRST_SIGNATURE);
+
+ assertTrue(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertTrue(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerInLineage_returnsTrue()
+ throws Exception {
+ // if a single signer is in the lineage and that previous signer has the requested
+ // capability then this method should return true.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerInLineageWOCapability_returnsFalse()
+ throws Exception {
+ // If a single signer is in the lineage and that previous signer does not have the requested
+ // capability then this method should return false.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_singleSignerMatchesCurrentSigner_returnsTrue()
+ throws Exception {
+ // If a requesting app is signed by the same current signer as an app with a lineage the
+ // method should return true since the current signer is granted all capabilities.
+ SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES});
+ SigningDetails singleSignerDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersWithCommonSigner_returnsTrue()
+ throws Exception {
+ // This method is intended to allow granting a capability to another app that has a common
+ // signer in the lineage with the capability still granted; this test verifies when the
+ // current signers diverge but a common ancestor has the requested capability this method
+ // returns true.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersOneGrantsCapability_returnsTrue()
+ throws Exception {
+ // If apps have multiple common signers in the lineage with one denying the requested
+ // capability but the other granting it this method should return true.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_divergingSignersNoneGrantCapability_returnsFalse()
+ throws Exception {
+ // If apps have multiple common signers in the lineage with all denying the requested
+ // capability this method should return false.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, AUTH, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void
+ hasCommonSignerWithCapabilities_divergingSignersNoneGrantsAllCapabilities_returnsTrue()
+ throws Exception {
+ // If an app has multiple common signers in the lineage, each granting one of the requested
+ // capabilities but neither granting all this method should return false since a single
+ // common ancestor must grant all requested capabilities.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, PERMISSION, DEFAULT_CAPABILITIES});
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, FOURTH_SIGNATURE);
+
+ assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION | SHARED_USER_ID));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_currentSignerInLineageOfRequestingApp_returnsTrue()
+ throws Exception {
+ // If the current signer of an app is in the lineage of the requesting app then this method
+ // should return true since the current signer is granted all capabilities.
+ SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE);
+ SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE, THIRD_SIGNATURE);
+
+ assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails,
+ PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_currentSignerInLineageOfDeclaringApp_returnsTrue()
+ throws Exception {
+ // If the current signer of a requesting app with a lineage is in the lineage of the
+ // declaring app and that previous signature is granted the requested capability the method
+ // should return true.
+ SigningDetails declaringDetails = createSigningDetailsWithLineageAndCapabilities(
+ new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
+ new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES});
+ SigningDetails requestingDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
+ SECOND_SIGNATURE);
+
+ assertTrue(declaringDetails.hasCommonSignerWithCapability(requestingDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_oneSignerNullLineage_returns() throws Exception {
+ // While the pastSigningCertificates should only be null in the case of multiple current
+ // signers there are instances where this can be null with a single signer; verify that a
+ // null pastSigningCertificates array in either SigningDetails does not result in a
+ // NullPointerException.
+ SigningDetails firstDetails = createSigningDetails(true, FIRST_SIGNATURE);
+ SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
+ @Test
+ public void hasCommonSignerWithCapabilities_unknownSigner_returnsFalse() throws Exception {
+ // An unknown SigningDetails for either instance should immediately result in false being
+ // returned.
+ SigningDetails firstDetails = SigningDetails.UNKNOWN;
+ SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE);
+
+ assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION));
+ assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION));
+ }
+
private SigningDetails createSigningDetailsWithLineage(String... signers) throws Exception {
int[] capabilities = new int[signers.length];
for (int i = 0; i < capabilities.length; i++) {
@@ -629,10 +841,34 @@
}
private SigningDetails createSigningDetails(String... signers) throws Exception {
+ return createSigningDetails(false, signers);
+ }
+
+ private SigningDetails createSigningDetails(boolean useNullPastSigners, String... signers)
+ throws Exception {
Signature[] currentSignatures = new Signature[signers.length];
for (int i = 0; i < signers.length; i++) {
currentSignatures[i] = new Signature(signers[i]);
}
- return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, null);
+ // If there are multiple signers then the pastSigningCertificates should be set to null, but
+ // if there is only a single signer both the current signer and the past signers should be
+ // set to that one signer.
+ if (signers.length > 1) {
+ return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, null);
+ }
+ return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, currentSignatures);
+ }
+
+ private void assertSigningDetailsContainsLineage(SigningDetails details,
+ String... pastSigners) {
+ // This method should only be invoked for results that contain a single signer.
+ assertEquals(1, details.signatures.length);
+ assertTrue(details.signatures[0].toCharsString().equalsIgnoreCase(
+ pastSigners[pastSigners.length - 1]));
+ Set<String> signatures = new ArraySet<>(pastSigners);
+ for (Signature pastSignature : details.pastSigningCertificates) {
+ assertTrue(signatures.remove(pastSignature.toCharsString()));
+ }
+ assertEquals(0, signatures.size());
}
}
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index d02c6d5..a5261ae 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -22,6 +22,8 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -30,6 +32,7 @@
import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
+import android.graphics.Path;
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -130,6 +133,8 @@
@Test
public void testHasCutout_noCutout() throws Exception {
assertTrue(NO_CUTOUT.isBoundsEmpty());
+ assertThat(NO_CUTOUT.getWaterfallInsets(), equalTo(Insets.NONE));
+ assertThat(NO_CUTOUT.getCutoutPath(), nullValue());
}
@Test
@@ -165,6 +170,59 @@
}
@Test
+ public void testGetCutoutPath() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE);
+ assertThat(cutout.getCutoutPath(), notNullValue());
+ }
+
+ @Test
+ public void testGetCutoutPath_caches() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final Path first = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ final Path second = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ assertThat(first, equalTo(second));
+ }
+
+ @Test
+ public void testGetCutoutPath_wontCacheIfCutoutPathParerInfoChanged() throws Exception {
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final Path first = fromSpec("L1,0 L1,1 L0,1 z", displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ final Path second = fromSpec("L2,0 L2,2 L0,2 z", displayWidth, displayHeight,
+ density, Insets.NONE).getCutoutPath();
+ assertThat(first, not(equalTo(second)));
+ }
+
+ @Test
+ public void testGetCutoutPathParserInfo() throws Exception {
+ final String cutoutSpecString = "L1,0 L1,1 L0,1 z";
+ final int displayWidth = 200;
+ final int displayHeight = 400;
+ final float density = 1f;
+ final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight,
+ density, Insets.NONE);
+ assertThat(displayWidth, equalTo(cutout.getCutoutPathParserInfo().getDisplayWidth()));
+ assertThat(displayHeight, equalTo(cutout.getCutoutPathParserInfo().getDisplayHeight()));
+ assertThat(density, equalTo(cutout.getCutoutPathParserInfo().getDensity()));
+ assertThat(cutoutSpecString.trim(),
+ equalTo(cutout.getCutoutPathParserInfo().getCutoutSpec()));
+ assertThat(0, equalTo(cutout.getCutoutPathParserInfo().getRotation()));
+ assertThat(1f, equalTo(cutout.getCutoutPathParserInfo().getScale()));
+ }
+
+ @Test
public void testHashCode() throws Exception {
assertEquals(mCutoutWithWaterfall.hashCode(), createCutoutWithWaterfall().hashCode());
assertNotEquals(mCutoutWithWaterfall.hashCode(), mCutoutNumbers.hashCode());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 1df2a4a..bb8a973 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -225,8 +225,9 @@
mTaskOrganizer.applyTransaction(wct);
// TODO(b/151449487): Only call callback once we enable synchronization
if (mListener != null) {
+ final int taskId = mTaskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
+ mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated);
});
}
}
@@ -256,8 +257,10 @@
}
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
+ final ComponentName baseActivity = taskInfo.baseActivity;
mListenerExecutor.execute(() -> {
- mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity);
+ mListener.onTaskCreated(taskId, baseActivity);
});
}
}
@@ -267,8 +270,9 @@
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onTaskRemovalStarted(taskInfo.taskId);
+ mListener.onTaskRemovalStarted(taskId);
});
}
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
@@ -289,8 +293,9 @@
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
if (mListener != null) {
+ final int taskId = taskInfo.taskId;
mListenerExecutor.execute(() -> {
- mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
+ mListener.onBackPressedOnTaskRoot(taskId);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 3181dbf..58a4baf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -356,11 +356,11 @@
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return null;
}
- final Insets waterfallInsets =
- RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
return computeSafeInsets(cutout, displayWidth, displayHeight);
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
Rect[] cutoutRects = cutout.getBoundingRectsAll();
final Rect[] newBounds = new Rect[cutoutRects.length];
@@ -372,8 +372,12 @@
}
newBounds[getBoundIndexFromRotation(i, rotation)] = rect;
}
+ final DisplayCutout.CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
+ final DisplayCutout.CutoutPathParserInfo newInfo = new DisplayCutout.CutoutPathParserInfo(
+ info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
+ info.getCutoutSpec(), rotation, info.getScale());
return computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
+ DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
rotated ? displayHeight : displayWidth,
rotated ? displayWidth : displayHeight);
}
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
index 4874d3c..a4cd3c5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -47,6 +47,11 @@
}
@Override
+ public void removeAllCallbacks() {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ @Override
public void removeCallbacks(@NonNull Runnable r) {
mHandler.removeCallbacks(r);
}
@@ -55,9 +60,4 @@
public boolean hasCallback(Runnable r) {
return mHandler.hasCallbacks(r);
}
-
- @Override
- public Looper getLooper() {
- return mHandler.getLooper();
- }
}
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
index 1149cce..b736fb0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -73,6 +73,11 @@
void executeDelayed(Runnable runnable, long delayMillis);
/**
+ * Removes all pending callbacks.
+ */
+ void removeAllCallbacks();
+
+ /**
* See {@link android.os.Handler#removeCallbacks}.
*/
void removeCallbacks(Runnable runnable);
@@ -81,9 +86,4 @@
* See {@link android.os.Handler#hasCallbacks(Runnable)}.
*/
boolean hasCallback(Runnable runnable);
-
- /**
- * Returns the looper that this executor is running on.
- */
- Looper getLooper();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
index d22abe4..125e322 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
@@ -24,6 +24,7 @@
import android.view.SurfaceControl;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
+import android.window.WindowContainerToken;
import androidx.annotation.VisibleForTesting;
@@ -55,7 +56,7 @@
private final Interpolator mOvershootInterpolator;
private final OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final HashMap<SurfaceControl, OneHandedTransitionAnimator> mAnimatorMap =
+ private final HashMap<WindowContainerToken, OneHandedTransitionAnimator> mAnimatorMap =
new HashMap<>();
/**
@@ -67,23 +68,23 @@
}
@SuppressWarnings("unchecked")
- OneHandedTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds,
- Rect endBounds) {
- final OneHandedTransitionAnimator animator = mAnimatorMap.get(leash);
+ OneHandedTransitionAnimator getAnimator(WindowContainerToken token, SurfaceControl leash,
+ Rect startBounds, Rect endBounds) {
+ final OneHandedTransitionAnimator animator = mAnimatorMap.get(token);
if (animator == null) {
- mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
- OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
+ mAnimatorMap.put(token, setupOneHandedTransitionAnimator(
+ OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds)));
} else if (animator.isRunning()) {
animator.updateEndValue(endBounds);
} else {
animator.cancel();
- mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
- OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
+ mAnimatorMap.put(token, setupOneHandedTransitionAnimator(
+ OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds)));
}
- return mAnimatorMap.get(leash);
+ return mAnimatorMap.get(token);
}
- HashMap<SurfaceControl, OneHandedTransitionAnimator> getAnimatorMap() {
+ HashMap<WindowContainerToken, OneHandedTransitionAnimator> getAnimatorMap() {
return mAnimatorMap;
}
@@ -91,8 +92,8 @@
return mAnimatorMap.isEmpty();
}
- void removeAnimator(SurfaceControl key) {
- final OneHandedTransitionAnimator animator = mAnimatorMap.remove(key);
+ void removeAnimator(WindowContainerToken token) {
+ final OneHandedTransitionAnimator animator = mAnimatorMap.remove(token);
if (animator != null && animator.isRunning()) {
animator.cancel();
}
@@ -116,6 +117,7 @@
ValueAnimator.AnimatorListener {
private final SurfaceControl mLeash;
+ private final WindowContainerToken mToken;
private T mStartValue;
private T mEndValue;
private T mCurrentValue;
@@ -128,8 +130,10 @@
private @TransitionDirection int mTransitionDirection;
- private OneHandedTransitionAnimator(SurfaceControl leash, T startValue, T endValue) {
+ private OneHandedTransitionAnimator(WindowContainerToken token, SurfaceControl leash,
+ T startValue, T endValue) {
mLeash = leash;
+ mToken = token;
mStartValue = startValue;
mEndValue = endValue;
addListener(this);
@@ -208,8 +212,8 @@
return this;
}
- SurfaceControl getLeash() {
- return mLeash;
+ WindowContainerToken getToken() {
+ return mToken;
}
Rect getDestinationBounds() {
@@ -254,10 +258,10 @@
}
@VisibleForTesting
- static OneHandedTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
- Rect startValue, Rect endValue) {
+ static OneHandedTransitionAnimator<Rect> ofBounds(WindowContainerToken token,
+ SurfaceControl leash, Rect startValue, Rect endValue) {
- return new OneHandedTransitionAnimator<Rect>(leash, new Rect(startValue),
+ return new OneHandedTransitionAnimator<Rect>(token, leash, new Rect(startValue),
new Rect(endValue)) {
private final Rect mTmpRect = new Rect();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index a74f476..37a91d0c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -56,7 +56,7 @@
private final float[] mColor;
private final float mAlpha;
private final Rect mRect;
- private final Handler mHandler;
+ private final Executor mMainExecutor;
private final Point mDisplaySize = new Point();
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -76,13 +76,13 @@
@Override
public void onOneHandedAnimationStart(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mHandler.post(() -> showBackgroundPanelLayer());
+ mMainExecutor.execute(() -> showBackgroundPanelLayer());
}
};
@Override
public void onStopFinished(Rect bounds) {
- mHandler.post(() -> removeBackgroundPanelLayer());
+ mMainExecutor.execute(() -> removeBackgroundPanelLayer());
}
public OneHandedBackgroundPanelOrganizer(Context context, DisplayController displayController,
@@ -94,7 +94,7 @@
mColor = new float[]{defaultRGB, defaultRGB, defaultRGB};
mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha);
mRect = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
- mHandler = new Handler();
+ mMainExecutor = executor;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index d2d5591..1da72f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -26,11 +26,11 @@
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.ArrayMap;
-import android.util.Log;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -44,8 +44,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
/**
* Manages OneHanded display areas such as offset.
@@ -69,7 +67,7 @@
private int mEnterExitAnimationDurationMs;
@VisibleForTesting
- ArrayMap<DisplayAreaInfo, SurfaceControl> mDisplayAreaMap = new ArrayMap();
+ ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaTokenMap = new ArrayMap();
private DisplayController mDisplayController;
private OneHandedAnimationController mAnimationController;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
@@ -89,7 +87,7 @@
@Override
public void onOneHandedAnimationEnd(SurfaceControl.Transaction tx,
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mAnimationController.removeAnimator(animator.getLeash());
+ mAnimationController.removeAnimator(animator.getToken());
if (mAnimationController.isAnimatorsConsumed()) {
finishOffset(animator.getDestinationOffset(),
animator.getTransitionDirection());
@@ -99,7 +97,7 @@
@Override
public void onOneHandedAnimationCancel(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mAnimationController.removeAnimator(animator.getLeash());
+ mAnimationController.removeAnimator(animator.getToken());
if (mAnimationController.isAnimatorsConsumed()) {
finishOffset(animator.getDestinationOffset(),
animator.getTransitionDirection());
@@ -119,7 +117,6 @@
super(mainExecutor);
mAnimationController = animationController;
mDisplayController = displayController;
- mDefaultDisplayBounds.set(getDisplayBounds());
mLastVisualDisplayBounds.set(getDisplayBounds());
final int animationDurationConfig = context.getResources().getInteger(
R.integer.config_one_handed_translate_animation_duration);
@@ -134,24 +131,12 @@
@Override
public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
@NonNull SurfaceControl leash) {
- Objects.requireNonNull(displayAreaInfo, "displayAreaInfo must not be null");
- Objects.requireNonNull(leash, "leash must not be null");
- if (mDisplayAreaMap.get(displayAreaInfo) == null) {
- // mDefaultDisplayBounds may out of date after removeDisplayChangingController()
- mDefaultDisplayBounds.set(getDisplayBounds());
- mDisplayAreaMap.put(displayAreaInfo, leash);
- }
+ mDisplayAreaTokenMap.put(displayAreaInfo.token, leash);
}
@Override
public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
- Objects.requireNonNull(displayAreaInfo,
- "Requires valid displayArea, and displayArea must not be null");
- if (!mDisplayAreaMap.containsKey(displayAreaInfo)) {
- Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
- return;
- }
- mDisplayAreaMap.remove(displayAreaInfo);
+ mDisplayAreaTokenMap.remove(displayAreaInfo.token);
}
@Override
@@ -162,6 +147,7 @@
final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
}
+ mDefaultDisplayBounds.set(getDisplayBounds());
return displayAreaInfos;
}
@@ -176,9 +162,9 @@
* handles 90 degree display rotation changes {@link Surface.Rotation}.
*
* @param fromRotation starting rotation of the display.
- * @param toRotation target rotation of the display (after rotating).
- * @param wct A task transaction {@link WindowContainerTransaction} from
- * {@link DisplayChangeController} to populate.
+ * @param toRotation target rotation of the display (after rotating).
+ * @param wct A task transaction {@link WindowContainerTransaction} from
+ * {@link DisplayChangeController} to populate.
*/
public void onRotateDisplay(int fromRotation, int toRotation, WindowContainerTransaction wct) {
// Stop one handed without animation and reset cropped size immediately
@@ -210,11 +196,11 @@
: TRANSITION_DIRECTION_EXIT;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- mDisplayAreaMap.forEach(
- (key, leash) -> {
- animateWindows(leash, fromBounds, toBounds, direction,
+ mDisplayAreaTokenMap.forEach(
+ (token, leash) -> {
+ animateWindows(token, leash, fromBounds, toBounds, direction,
mEnterExitAnimationDurationMs);
- wct.setBounds(key.token, toBounds);
+ wct.setBounds(token, toBounds);
});
applyTransaction(wct);
}
@@ -222,10 +208,10 @@
private void resetWindowsOffset(WindowContainerTransaction wct) {
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
- mDisplayAreaMap.forEach(
- (key, leash) -> {
+ mDisplayAreaTokenMap.forEach(
+ (token, leash) -> {
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
- mAnimationController.getAnimatorMap().remove(leash);
+ mAnimationController.getAnimatorMap().remove(token);
if (animator != null && animator.isRunning()) {
animator.cancel();
}
@@ -233,16 +219,17 @@
.setWindowCrop(leash, -1/* reset */, -1/* reset */);
// DisplayRotationController will applyTransaction() after finish rotating
if (wct != null) {
- wct.setBounds(key.token, null/* reset */);
+ wct.setBounds(token, null/* reset */);
}
});
tx.apply();
}
- private void animateWindows(SurfaceControl leash, Rect fromBounds, Rect toBounds,
- @OneHandedAnimationController.TransitionDirection int direction, int durationMs) {
+ private void animateWindows(WindowContainerToken token, SurfaceControl leash, Rect fromBounds,
+ Rect toBounds, @OneHandedAnimationController.TransitionDirection int direction,
+ int durationMs) {
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
- mAnimationController.getAnimator(leash, fromBounds, toBounds);
+ mAnimationController.getAnimator(token, leash, fromBounds, toBounds);
if (animator != null) {
animator.setTransitionDirection(direction)
.addOneHandedAnimationCallback(mOneHandedAnimationCallback)
@@ -311,8 +298,8 @@
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mIsInOneHanded=");
pw.println(mIsInOneHanded);
- pw.print(innerPrefix + "mDisplayAreaMap=");
- pw.println(mDisplayAreaMap);
+ pw.print(innerPrefix + "mDisplayAreaTokenMap=");
+ pw.println(mDisplayAreaTokenMap);
pw.print(innerPrefix + "mDefaultDisplayBounds=");
pw.println(mDefaultDisplayBounds);
pw.print(innerPrefix + "mLastVisualDisplayBounds=");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
index 1ed121f..49b7e05 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
@@ -221,8 +221,14 @@
displaySize.y);
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"onehanded-gesture-offset", DEFAULT_DISPLAY);
- mInputEventReceiver = new EventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new EventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
index 60709be..c7a49ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java
@@ -132,8 +132,14 @@
if (mIsEnabled) {
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"onehanded-touch", DEFAULT_DISPLAY);
- mInputEventReceiver = new EventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new EventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 7a634c3..6e3a20d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -147,7 +147,7 @@
// Choreographer.getSfInstance() must be called on the thread that the input event
// receiver should be receiving events
mInputEventReceiver = new InputEventReceiver(inputChannel,
- mMainExecutor.getLooper(), Choreographer.getSfInstance());
+ Looper.myLooper(), Choreographer.getSfInstance());
if (mRegistrationListener != null) {
mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 41cc59d..8fb358a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -212,8 +212,14 @@
// Register input event receiver
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"pip-resize", mDisplayId);
- mInputEventReceiver = new PipResizeInputEventReceiver(
- mInputMonitor.getInputChannel(), mMainExecutor.getLooper());
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ mInputEventReceiver = new PipResizeInputEventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ });
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to create input event receiver", e);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index c9f5ae2..2b8b53c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -95,7 +95,6 @@
private int mDeferResizeToNormalBoundsUntilRotation = -1;
private int mDisplayRotation;
- private final Handler mHandler = new Handler();
private final PipAccessibilityInteractionConnection mConnection;
// Behaviour states
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index af99543..224cc19 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -162,6 +163,7 @@
}
}
+ @FlakyTest(bugId = 173875043)
@Test
fun testNonResizeableNotDocked() {
val testTag = "testNonResizeableNotDocked"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
index 785ccf0..870adb8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -113,6 +114,7 @@
}
}
+ @FlakyTest(bugId = 173875043)
@Test
fun testRotateAndEnterSplitScreenMode() {
val testTag = "testRotateAndEnterSplitScreenMode"
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
index 5f5c30b..bf84a6e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
@@ -40,6 +40,11 @@
}
@Override
+ public void removeAllCallbacks() {
+ mRunnables.clear();
+ }
+
+ @Override
public void removeCallbacks(Runnable r) {
mRunnables.remove(r);
}
@@ -49,11 +54,6 @@
return mRunnables.contains(r);
}
- @Override
- public Looper getLooper() {
- return null;
- }
-
public void flushAll() {
for (Runnable r : mRunnables) {
r.run();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java
index 17fc057..8d5139b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java
@@ -22,6 +22,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -50,6 +51,8 @@
@Mock
private SurfaceControl mMockLeash;
+ @Mock
+ private WindowContainerToken mMockToken;
@Mock
private ShellExecutor mMainExecutor;
@@ -69,7 +72,7 @@
destinationBounds.offset(0, 300);
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
mOneHandedAnimationController
- .getAnimator(mMockLeash, originalBounds, destinationBounds);
+ .getAnimator(mMockToken, mMockLeash, originalBounds, destinationBounds);
assertNotNull(animator);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 6cfd0c4..01162b5c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -24,13 +24,14 @@
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
-import android.os.Handler;
+import android.os.Binder;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
@@ -89,12 +90,14 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ Binder binder = new Binder();
+ doReturn(binder).when(mMockRealToken).asBinder();
mToken = new WindowContainerToken(mMockRealToken);
mLeash = new SurfaceControl();
mDisplay = mContext.getDisplay();
mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED);
mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
- when(mMockAnimationController.getAnimator(any(), any(), any())).thenReturn(null);
+ when(mMockAnimationController.getAnimator(any(), any(), any(), any())).thenReturn(null);
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockSurfaceTransactionHelper.translate(any(), any(), anyFloat())).thenReturn(
mMockSurfaceTransactionHelper);
@@ -121,7 +124,7 @@
public void testOnDisplayAreaAppeared() {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
- verify(mMockAnimationController, never()).getAnimator(any(), any(), any());
+ verify(mMockAnimationController, never()).getAnimator(any(), any(), any(), any());
}
@Test
@@ -129,7 +132,7 @@
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
mDisplayAreaOrganizer.onDisplayAreaVanished(mDisplayAreaInfo);
- assertThat(mDisplayAreaOrganizer.mDisplayAreaMap).isEmpty();
+ assertThat(mDisplayAreaOrganizer.mDisplayAreaTokenMap).isEmpty();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
index 9219f15..bbe8891 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandlerTest.java
@@ -33,6 +33,7 @@
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
@@ -48,7 +49,7 @@
@RunWith(AndroidTestingRunner.class)
public class OneHandedTimeoutHandlerTest extends OneHandedTestCase {
private OneHandedTimeoutHandler mTimeoutHandler;
- private ShellExecutor mMainExecutor;
+ private TestShellExecutor mMainExecutor;
@Before
public void setUp() throws Exception {
@@ -104,34 +105,4 @@
mTimeoutHandler.resetTimer();
assertTrue(mTimeoutHandler.hasScheduledTimeout());
}
-
- private class TestShellExecutor implements ShellExecutor {
- private ArrayList<Runnable> mExecuted = new ArrayList<>();
- private ArrayList<Runnable> mDelayed = new ArrayList<>();
-
- @Override
- public void execute(Runnable runnable) {
- mExecuted.add(runnable);
- }
-
- @Override
- public void executeDelayed(Runnable r, long delayMillis) {
- mDelayed.add(r);
- }
-
- @Override
- public void removeCallbacks(Runnable r) {
- mDelayed.remove(r);
- }
-
- @Override
- public boolean hasCallback(Runnable r) {
- return mDelayed.contains(r);
- }
-
- @Override
- public Looper getLooper() {
- return Looper.myLooper();
- }
- }
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 6f4f72a..3837743 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Sal nie outomaties koppel nie"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Geen internettoegang nie"</string>
<string name="saved_network" msgid="7143698034077223645">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Outomaties deur %1$s gekoppel"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Outomaties deur netwerkgraderingverskaffer gekoppel"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Gekoppel via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 3f5df34..4ce01d6 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"በራስ-ሰር አይገናኝም"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
<string name="saved_network" msgid="7143698034077223645">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"በ%1$s በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"በአውታረ መረብ ደረጃ ሰጪ አቅራቢ በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"በ%1$s በኩል መገናኘት"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 0351d94..2580d0f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"لن يتم الاتصال تلقائيًا"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"لا يتوفّر اتصال بالإنترنت"</string>
<string name="saved_network" msgid="7143698034077223645">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"تم الاتصال تلقائيًا عبر %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"تم الاتصال تلقائيًا عبر مقدم خدمة تقييم الشبكة"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"تم الاتصال عبر %1$s"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 0f7db8f..b61ff50 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ’ব"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ইণ্টাৰনেট সংযোগ নাই"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>এ ছেভ কৰিছে"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ’ল"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 0855d17e..d063776 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Avtomatik qoşulmayacaq"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"İnternet girişi yoxdur"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s üzərindən avtomatik qoşuldu"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Avtomatik olaraq şəbəkə reytinq provayderi ilə qoşuludur"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s vasitəsilə qoşuludur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3386fe86..2976bb5 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Automatsko povezivanje nije uspelo"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezano preko %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezano preko dobavljača ocene mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 6ac2172..7af9e93 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не будзе аўтаматычна падключацца"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Няма доступу да інтэрнэту"</string>
<string name="saved_network" msgid="7143698034077223645">"Захавана праз: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Аўтаматычна падключана праз %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Аўтаматычна падключана праз пастаўшчыка паслугі ацэнкі сеткі"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Падключана праз %1$s"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 19ed5bd..77b6493 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Няма да се свърже автоматично"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Няма достъп до интернет"</string>
<string name="saved_network" msgid="7143698034077223645">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматично е установена връзка чрез %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматично е установена връзка чрез доставчик на услуги за оценяване на мрежите"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Установена е връзка през „%1$s“"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index b0e9342..819625b 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"অটোমেটিক কানেক্ট করবে না"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ইন্টারনেট অ্যাক্সেস নেই"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সেভ করা"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"স্বয়ংক্রিয়ভাবে %1$s এর মাধ্যমে কানেক্ট হয়েছে"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"নেটওয়ার্কের রেটিং প্রদানকারীর মাধ্যমে অটোমেটিক কানেক্ট"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s মাধ্যমে কানেক্ট হয়েছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 9377624..193ac60 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Neće se automatski povezati"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Sačuvano: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezano koristeći %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezano putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Povezani preko %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index a2a7770..fef9bfb 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No es connectarà automàticament"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Desada per <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Connectada automàticament a través de: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connectada mitjançant %1$s"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 4db4d5c..281a788 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Připojení nebude automaticky navázáno"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nebyl zjištěn žádný přístup k internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaticky připojeno přes poskytovatele %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automaticky připojeno přes poskytovatele hodnocení sítí"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Připojeno prostřednictvím %1$s"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index b76afa5c..69cc8d8 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Der oprettes ikke automatisk forbindelse"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internetadgang"</string>
<string name="saved_network" msgid="7143698034077223645">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisk tilsluttet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisk forbundet via udbyder af netværksvurdering"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tilsluttet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index ba760dd..737ea16 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Kein automatischer Verbindungsaufbau"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Kein Internetzugriff"</string>
<string name="saved_network" msgid="7143698034077223645">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisch über %1$s verbunden"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch über Anbieter von Netzwerkbewertungen verbunden"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Über %1$s verbunden"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index c608a62..8e1d5e3 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Δεν θα συνδεθεί αυτόματα"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
<string name="saved_network" msgid="7143698034077223645">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Συνδέθηκε αυτόματα μέσω %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Συνδέθηκε αυτόματα μέσω παρόχου αξιολόγησης δικτύου"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Συνδέθηκε μέσω %1$s"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index e67c3d1..b98c4b8 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Won\'t automatically connect"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No Internet access"</string>
<string name="saved_network" msgid="7143698034077223645">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connected to metered network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatically connected via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatically connected via network rating provider"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connected via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index b0830fc..aa0d3f1 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Won\'t automatically connect"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No Internet access"</string>
<string name="saved_network" msgid="7143698034077223645">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connected to metered network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatically connected via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatically connected via network rating provider"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connected via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index e67c3d1..b98c4b8 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Won\'t automatically connect"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No Internet access"</string>
<string name="saved_network" msgid="7143698034077223645">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connected to metered network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatically connected via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatically connected via network rating provider"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connected via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index e67c3d1..b98c4b8 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Won\'t automatically connect"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No Internet access"</string>
<string name="saved_network" msgid="7143698034077223645">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connected to metered network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatically connected via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatically connected via network rating provider"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connected via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 4c0af75..c01f3a0 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Won\'t automatically connect"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No internet access"</string>
<string name="saved_network" msgid="7143698034077223645">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connected to metered network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatically connected via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatically connected via network rating provider"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connected via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 9ae7781..f79072f 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No se conectará automáticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No hay acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conexión automática mediante %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automáticamente mediante proveedor de calificación de red"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conexión a través de %1$s"</string>
@@ -116,8 +118,8 @@
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"La sincronización te permite acceder a los contactos y al historial de llamadas cuando el dispositivo está conectado."</string>
- <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que el PIN o la clave de acceso son incorrectos."</string>
+ <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"No se pudo vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"No se pudo vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que el PIN o la clave de acceso son incorrectos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"No se puede establecer la comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Vínculo rechazado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Computadora"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 203726a..f99a3f1 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No se establecerá conexión automáticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No se ha detectado ningún acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectada automáticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automáticamente a través de un proveedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 379ed6c..fa2aa46 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Automaatselt ei ühendata"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Juurdepääs Internetile puudub"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ühendus loodi automaatselt teenusega %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ühendus loodi automaatselt võrgukvaliteedi hinnangute pakkuja kaudu"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Ühendatud üksuse %1$s kaudu"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 2582854..2c4a8ee 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Ez da konektatuko automatikoki"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ezin da konektatu Internetera"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s bidez automatikoki konektatuta"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatikoki konektatuta sare-balorazioen hornitzailearen bidez"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s bidez konektatuta"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index cb598e5..1c6ca76 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"اتصال بهصورت خودکار انجام نمیشود"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"دسترسی به اینترنت ندارد"</string>
<string name="saved_network" msgid="7143698034077223645">"ذخیرهشده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"اتصال خودکار ازطریق %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"اتصال خودکار ازطریق ارائهدهنده رتبهبندی شبکه"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"متصل از طریق %1$s"</string>
@@ -263,8 +265,8 @@
<string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"انتخاب نسخه MAP بلوتوث"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"کدک بلوتوث صوتی"</string>
<string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"راهاندازی کدک صوتی بلوتوثی\nانتخاب"</string>
- <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"سرعت نمونه بلوتوث صوتی"</string>
- <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"راهاندازی کدک صوتی بلوتوثی\nانتخاب: سرعت نمونه"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"بسامد نمونه صوتی بلوتوث"</string>
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"راهاندازی کدک صوتی بلوتوثی\nانتخاب: بسامد نمونه"</string>
<string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"«خاکستری» به این معناست که تلفن یا هدست از آن پشتیبانی نمیکند"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"بیتهای بلوتوث صوتی در هر نمونه"</string>
<string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"راهاندازی کدک صوتی بلوتوثی\nانتخاب: تعداد بیت در نمونه"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 31dfe18..04c9130 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Yhteyttä ei muodosteta automaattisesti"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ei internetyhteyttä"</string>
<string name="saved_network" msgid="7143698034077223645">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaattinen yhteys muodostettu palvelun %1$s kautta"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Yhdistetty automaattisesti verkon arviointipalvelun kautta"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Yhdistetty seuraavan kautta: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index a8476dd..aa0cd2a 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Reconnexion automatique impossible"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiquement connecté par %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connecté automatiquement par le fournisseur d\'avis sur le réseau"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connecté par %1$s"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index a79ed0c..dbdc160 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Reconnexion automatique impossible"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Enregistré lors de : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Connecté automatiquement via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connecté automatiquement via un fournisseur d\'évaluation de l\'état du réseau"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connecté via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 97662a6..90c1303 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Non se conectará automaticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Sen acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Gardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectouse automaticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 46bd71b..4caeda2 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ઑટોમૅટિક રીતે કનેક્ટ કરશે નહીં"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s દ્વારા સ્વત: કનેક્ટ થયેલ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા ઑટોમૅટિક રીતે કનેક્ટ થયું"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9cae311..468808b 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"अपने आप कनेक्ट नहीं होगा"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इंटरनेट नहीं है"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s के ज़रिए ऑटोमैटिक रूप से कनेक्ट है"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्क रेटिंग कंपनी के ज़रिए अपने आप कनेक्ट है"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s के द्वारा उपलब्ध"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 83bb2d1..932c256 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Neće se povezati automatski"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Spremila aplik. <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezan putem %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezan putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Povezano putem %1$s"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9f184c7..fbaffac 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nem csatlakozik automatikusan"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nincs internet-hozzáférés"</string>
<string name="saved_network" msgid="7143698034077223645">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatikusan csatlakozott a következőn keresztül: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatikusan csatlakozott a hálózatértékelés szolgáltatóján keresztül"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Csatlakozva a következőn keresztül: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index cd6cbf3..224d641 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Չի միանա ավտոմատ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="7143698034077223645">"Ով է պահել՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ միացել է ցանցերի վարկանիշի մատակարարի միջոցով"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Միացված է %1$s-ի միջոցով"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3b80918..8cf13cd 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan tersambung otomatis"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Tidak ada akses internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Tersambung otomatis melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis tersambung melalui penyedia rating jaringan"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Terhubung melalui %1$s"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index ce9e665..aa8893e 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Mun ekki tengjast sjálfkrafa"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Enginn netaðgangur"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Sjálfkrafa tengt um %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Sjálfkrafa tengt um netgæðaveitu"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tengt í gegnum %1$s"</string>
@@ -226,12 +228,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi-Fi pörunarkóði"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Pörun mistókst"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Gakktu úr skugga um að tækið sé tengt sama neti."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Tengja tæki með Wi-Fi með því að skanna QR-kóða"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Para tæki gegnum Wi-Fi með því að skanna QR-kóða"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Parar tæki…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Ekki tókst að para við tækið. Annað hvort var QR-kóðinn rangur eða tækið ekki tengt sama neti."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-tala og gátt"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skanna QR-kóða"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Tengja tæki með Wi-Fi með því að skanna QR-kóða"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Para tæki gegnum Wi-Fi með því að skanna QR-kóða"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Tengstu Wi-Fi neti"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, villuleit, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Flýtileið í villutilkynningu"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 93b24a0..0199f54 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Non verrà eseguita la connessione automatica"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nessun accesso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Collegato automaticamente tramite %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Collegato automaticamente tramite fornitore di servizi di valutazione rete"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Collegato tramite %1$s"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index ab67809..a50a22d 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"לא יתבצע חיבור באופן אוטומטי"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"אין גישה לאינטרנט"</string>
<string name="saved_network" msgid="7143698034077223645">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"מחובר אוטומטית דרך %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"מחובר אוטומטית דרך ספק של דירוג רשת"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"מחובר דרך %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 711a22f..a1d1b70 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"自動的に接続されません"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"インターネット接続なし"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s 経由で自動的に接続しています"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ネットワーク評価プロバイダ経由で自動的に接続しています"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s経由で接続"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 0813305..77fd4b1 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ავტომატურად დაკავშირება ვერ მოხერხდება"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ინტერნეტ-კავშირი არ არის"</string>
<string name="saved_network" msgid="7143698034077223645">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"ავტომატურად დაკავშირდა %1$s-ის მეშვეობით"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ავტომატურად დაკავშირდა ქსელის ხარისხის შეფასების პროვაიდერის მეშვეობით"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-ით დაკავშირებული"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 16ee9c0..eb5cd54 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматты қосылмайды"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернетпен байланыс жоқ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s арқылы автоматты қосылды"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Желі рейтингі провайдері арқылы автоматты түрде қосылған"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s арқылы қосылған"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 5b47381..38abb80 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
<string name="saved_network" msgid="7143698034077223645">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈ %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈក្រុមហ៊ុនផ្តល់ការវាយតម្លៃលើបណ្តាញ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"បានភ្ជាប់តាមរយៈ %1$s"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index fd63dcb..560fba15 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ನಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ನೆಟ್ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a9c3f31..f43ce16 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"자동으로 연결되지 않습니다."</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"인터넷에 연결되어 있지 않음"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s을(를) 통해 자동으로 연결됨"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"네트워크 평가 제공업체를 통해 자동으로 연결됨"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s을(를) 통해 연결됨"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index bc3656f..35b1ecac 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматтык түрдө туташпайт"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернетке туташпай турат"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Тармактар рейтингинин булагы аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s аркылуу жеткиликтүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 8408c93..f60fe7f 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
<string name="saved_network" msgid="7143698034077223645">"ບັນທຶກໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"ເຊື່ອມຕໍ່ຜ່ານທາງ %1$s ໂດຍອັດຕະໂນມັດ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ເຊື່ອມຕໍ່ກັບອັດຕະໂນມັດແລ້ວຜ່ານຜູ້ໃຫ້ບໍລິການຄະແນນເຄືອຂ່າຍ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"ເຊື່ອມຕໍ່ຜ່ານ %1$s ແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 1dcfcf7..e66e3c5 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nebus automatiškai prisijungiama"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nėra interneto ryšio"</string>
<string name="saved_network" msgid="7143698034077223645">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiškai prisijungta naudojant „%1$s“"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatiškai prisijungta naudojant tinklo įvertinimo paslaugos teikėjo paslaugomis"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Prisijungta naudojant „%1$s“"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 3d9b78a..a8bd2cc 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Savienojums netiks izveidots automātiski"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nav piekļuves internetam"</string>
<string name="saved_network" msgid="7143698034077223645">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Izveidots savienojums ar maksas tīklu"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automātiski savienots, izmantojot %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automātiski izveidots savienojums, izmantojot tīkla vērtējuma sniedzēju"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Savienots, izmantojot %1$s"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0674f11..90bcc04 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не може да се поврзе автоматски"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Нема пристап до интернет"</string>
<string name="saved_network" msgid="7143698034077223645">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматски поврзано преку %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматски поврзано преку оценувач на мрежа"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Поврзано преку %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1455669..ba1987b 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"സ്വയമേവ കണക്റ്റുചെയ്യില്ല"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s വഴി സ്വയമേവ ബന്ധിപ്പിച്ചു"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"നെറ്റ്വർക്ക് റേറ്റിംഗ് ദാതാവുമായി സ്വയം കണക്റ്റുചെയ്തു"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index f13cb0b..45a831d 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматаар холбогдохгүй"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернет хандалт алга"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s-р автоматаар холбогдсон"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Сүлжээний үнэлгээ үзүүлэгчээр автоматаар холбогдох"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-р холбогдсон"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index aaf51b3..6cc0130 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -155,14 +155,28 @@
<item msgid="253388653486517049">", अॅक्टिव्ह (मीडिया)"</item>
<item msgid="5001852592115448348">", अॅक्टिव्ह (फोन)"</item>
</string-array>
- <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
+ <string-array name="select_logd_size_titles">
+ <item msgid="1191094707770726722">"बंद"</item>
+ <item msgid="7839165897132179888">"64K"</item>
+ <item msgid="2715700596495505626">"256K"</item>
+ <item msgid="7099386891713159947">"1M"</item>
+ <item msgid="6069075827077845520">"4M"</item>
+ <item msgid="6078203297886482480">"८MB"</item>
+ </string-array>
<string-array name="select_logd_size_lowram_titles">
<item msgid="1145807928339101085">"बंद"</item>
<item msgid="4064786181089783077">"64K"</item>
<item msgid="3052710745383602630">"256K"</item>
<item msgid="3691785423374588514">"1M"</item>
</string-array>
- <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
+ <string-array name="select_logd_size_summaries">
+ <item msgid="409235464399258501">"बंद"</item>
+ <item msgid="4195153527464162486">"प्रति लॉग बफर 64K"</item>
+ <item msgid="7464037639415220106">"प्रति लॉग बफर 256K"</item>
+ <item msgid="8539423820514360724">"प्रति लॉग बफर 1M"</item>
+ <item msgid="1984761927103140651">"प्रति लॉग बफर 4M"</item>
+ <item msgid="2983219471251787208">"८MB प्रति लॉग बफर"</item>
+ </string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"बंद"</item>
<item msgid="6014837961827347618">"सर्व"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 72ddc8f..1e69b28 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इंटरनेट अॅक्सेस नाही"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s द्वारे कनेक्ट केले"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 9527793..71c9eea 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan menyambung secara automatik"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Tiada akses Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Disambungkan secara automatik melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Disambungkan secara automatik melalui pembekal penilaian rangkaian"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Disambungkan melalui %1$s"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 1dcb3cf..3b3983e 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> က သိမ်းဆည်းခဲ့သည်"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ကွန်ရက်အဆင့်သတ်မှတ်ပေးသူ မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 13f69c1..a8c01b3 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Kobler ikke til automatisk"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internettilgang"</string>
<string name="saved_network" msgid="7143698034077223645">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisk tilkoblet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisk tilkoblet via leverandør av nettverksvurdering"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tilkoblet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 5795cc9..c285637 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"स्वतः जडान हुने छैन"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इन्टरनेटमाथिको पहुँच छैन"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s मार्फत् स्वतः जडान गरिएको"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्कको दर्जा प्रदायक मार्फत स्वत: जडान गरिएको"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s मार्फत जडित"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 718ce5d..9f4ea68 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Er wordt niet automatisch verbinding gemaakt"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Geen internettoegang"</string>
<string name="saved_network" msgid="7143698034077223645">"Opgeslagen door \'<xliff:g id="NAME">%1$s</xliff:g>\'"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisch verbonden via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch verbonden via provider van netwerkbeoordelingen"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Verbonden via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 41e84f9..31bd7af 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ସ୍ୱଚାଳିତ ଭାବେ ସଂଯୁକ୍ତ ହେବନାହିଁ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ଇଣ୍ଟରନେଟ୍ର କୌଣସି ଆକ୍ସେସ୍ ନାହିଁ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ଦ୍ୱାରା ସେଭ କରାଯାଇଛି"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲୀ ସଂଯୁକ୍ତ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ନେଟୱର୍କ ମୂଲ୍ୟାୟନ ପ୍ରଦାତାଙ୍କ ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲ୍ୟ ସଂଯୁକ୍ତ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index c64ee76..c6116aa 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -155,14 +155,28 @@
<item msgid="253388653486517049">", ਕਿਰਿਆਸ਼ੀਲ (ਮੀਡੀਆ)"</item>
<item msgid="5001852592115448348">", ਕਿਰਿਆਸ਼ੀਲ (ਫ਼ੋਨ)"</item>
</string-array>
- <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
+ <string-array name="select_logd_size_titles">
+ <item msgid="1191094707770726722">"ਬੰਦ"</item>
+ <item msgid="7839165897132179888">"64K"</item>
+ <item msgid="2715700596495505626">"256K"</item>
+ <item msgid="7099386891713159947">"1M"</item>
+ <item msgid="6069075827077845520">"4M"</item>
+ <item msgid="6078203297886482480">"8M"</item>
+ </string-array>
<string-array name="select_logd_size_lowram_titles">
<item msgid="1145807928339101085">"ਬੰਦ"</item>
<item msgid="4064786181089783077">"64K"</item>
<item msgid="3052710745383602630">"256K"</item>
<item msgid="3691785423374588514">"1M"</item>
</string-array>
- <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
+ <string-array name="select_logd_size_summaries">
+ <item msgid="409235464399258501">"ਬੰਦ"</item>
+ <item msgid="4195153527464162486">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="7464037639415220106">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="8539423820514360724">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="1984761927103140651">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
+ <item msgid="2983219471251787208">"8M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
+ </string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"ਬੰਦ"</item>
<item msgid="6014837961827347618">"ਸਭ"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e04e201..f21c4ce 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ਰਾਹੀਂ ਆਪਣੇ-ਆਪ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਰਾਹੀਂ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a57e541..c9c4a6c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nie można połączyć automatycznie"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Brak dostępu do internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatycznie połączono przez: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatycznie połączono przez dostawcę ocen jakości sieci"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Połączono przez %1$s"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index f24b52b..881bccb 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Não se conectará automaticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salva por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Conectado a uma rede limitada"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectado automaticamente via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automaticamente via provedor de avaliação de rede"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 42ad0fe..94cad918 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Não é efetuada uma ligação automaticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Sem acesso à Internet."</string>
<string name="saved_network" msgid="7143698034077223645">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Ligação estabelecida a uma rede de acesso limitado."</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ligado automaticamente através de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ligado automaticamente através do fornecedor de classificação de rede"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Ligado através de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index f24b52b..881bccb 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -36,6 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Não se conectará automaticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salva por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Conectado a uma rede limitada"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectado automaticamente via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automaticamente via provedor de avaliação de rede"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 0743fe9..4b71085 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nu se va conecta automat"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nu există acces la internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectată automat prin %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectată automat prin furnizor de evaluări ale rețelei"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectată prin %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index d19438a..4aeb985 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Подключение не будет выполняться автоматически"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Без доступа к Интернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматически подключено к %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматически подключено через автора рейтинга сетей"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Подключено к %1$s"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 15fe8c8..525d423 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ස්වයංක්රිය නැවත සම්බන්ධ නොවනු ඇත"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"අන්තර්ජාල ප්රවේශය නැත"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s හරහා ස්වයංක්රියව සම්බන්ධ විය"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ජාල ශ්රේණිගත සපයන්නා හරහා ස්වයංක්රියව සම්බන්ධ විය"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s හරහා සම්බන්ධ විය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index ee53b7c..ee9ae6a 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nedôjde k automatickému pripojeniu"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Žiadny prístup k internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Uložila aplikácia <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaticky pripojené prostredníctvom %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automaticky pripojené prostredníctvom poskytovateľa hodnotenia siete"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Pripojené prostredníctvom %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 66d33a7..ff60a32 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Samodejna vnovična vzpostavitev povezave se ne bo izvedla"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ni dostopa do interneta"</string>
<string name="saved_network" msgid="7143698034077223645">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Samodejno vzpostavljena povezava prek: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Samodejno vzpostavljena povezava prek ponudnika ocenjevanja omrežij"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Vzpostavljena povezava prek: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d5c0231..78e6ed6 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nuk do të lidhet automatikisht"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nuk ka qasje në internet"</string>
<string name="saved_network" msgid="7143698034077223645">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Lidhur automatikisht përmes %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Lidhur automatikisht nëpërmjet ofruesit të vlerësimit të rrjetit"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"E lidhur përmes %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index ce74b84..8bb9277 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Аутоматско повезивање није успело"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Нема приступа интернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Аутоматски повезано преко %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Аутоматски повезано преко добављача оцене мреже"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Веза је успостављена преко приступне тачке %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index eacb7a8..03fb223 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Det går inte att ansluta automatiskt"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internetåtkomst"</string>
<string name="saved_network" msgid="7143698034077223645">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiskt ansluten via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatiskt ansluten via leverantör av nätverksbetyg"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Anslutet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 62ae06b..b95d69c 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -161,7 +161,7 @@
<item msgid="2715700596495505626">"K256"</item>
<item msgid="7099386891713159947">"M1"</item>
<item msgid="6069075827077845520">"M4"</item>
- <item msgid="6078203297886482480">"M8"</item>
+ <item msgid="6078203297886482480">"MB 8"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
<item msgid="1145807928339101085">"Imezimwa"</item>
@@ -175,7 +175,7 @@
<item msgid="7464037639415220106">"K256 kwa kila akiba ya kumbukumbu"</item>
<item msgid="8539423820514360724">"M1 kwa kila akiba ya kumbukumbu"</item>
<item msgid="1984761927103140651">"M4 kwa kila akiba ya kumbukumbu"</item>
- <item msgid="2983219471251787208">"M8 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="2983219471251787208">"MB 8 kwa kila akiba ya kumbukumbu"</item>
</string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"Yamezimwa"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index e7045a7..631a413 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Haiwezi kuunganisha kiotomatiki"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Hakuna muunganisho wa intaneti"</string>
<string name="saved_network" msgid="7143698034077223645">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Imeunganishwa kiotomatiki kupitia %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Imeunganishwa kiotomatiki kupitia mtoa huduma wa ukadiriaji wa mtandao"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Imeunganishwa kupitia %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 06c7ccb..5796603 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"தானாக இணைக்கப்படாது"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"இண்டர்நெட் அணுகல் இல்லை"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s வழியாக இணைக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 5e880a9..9027ca1 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 6316452..8358dbb 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
<string name="saved_network" msgid="7143698034077223645">"บันทึกโดย<xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"เชื่อมต่ออัตโนมัติผ่าน %1$s แล้ว"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"เชื่อมต่ออัตโนมัติผ่านผู้ให้บริการการจัดอันดับเครือข่าย"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 0aabbe5..d5250a4 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Hindi awtomatikong kokonekta"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Walang access sa internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Na-save ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Awtomatikong nakakonekta sa pamamagitan ng %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Awtomatikong nakakonekta sa pamamagitan ng provider ng rating ng network"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Nakakonekta sa pamamagitan ng %1$s"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 44c8f13..8e0b889 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Otomatik olarak bağlanma"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"İnternet erişimi yok"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s üzerinden otomatik olarak bağlı"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ağ derecelendirme sağlayıcı aracılığıyla otomatik olarak bağlandı"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s üzerinden bağlı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 7851111..c2f71c3 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не під’єднуватиметься автоматично"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Немає доступу до Інтернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматично під’єднано через %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматично під’єднано через постачальника оцінки якості мережі"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Під’єднано через %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 82783b3..a0c5f94 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"خودکار طور پر منسلک نہیں ہو گا"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s کے ذریعے از خود منسلک کردہ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"نیٹ ورک درجہ بندی کے فراہم کنندہ کے ذریعے از خود منسلک"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"منسلک بذریعہ %1$s"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index c2a96c6..1fb610b 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Avtomatik ravishda ulanilmaydi"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Internet aloqasi yo‘q"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s orqali avtomatik ulandi"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Tarmoqlar reytingi muallifi orqali avtomatik ulandi"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s orqali ulangan"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2596424..1f3ea48 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Sẽ không tự động kết nối"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Không có quyền truy cập Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Do <xliff:g id="NAME">%1$s</xliff:g> lưu"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Tự động được kết nối qua %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Tự động được kết nối qua nhà cung cấp dịch vụ xếp hạng mạng"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Được kết nối qua %1$s"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 60afd6d..828d25f 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"无法自动连接"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"无法访问互联网"</string>
<string name="saved_network" msgid="7143698034077223645">"由“<xliff:g id="NAME">%1$s</xliff:g>”保存"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已通过%1$s自动连接"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已自动连接(通过网络评分服务提供方)"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已通过%1$s连接"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 925f738..54e1f41 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"不會自動連線"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"無法連接互聯網"</string>
<string name="saved_network" msgid="7143698034077223645">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已透過網絡評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已透過 %1$s 連線"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index e40d351..b8f1f58 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"無法自動連線"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"沒有可用的網際網路連線"</string>
<string name="saved_network" msgid="7143698034077223645">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已透過網路評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已透過 %1$s 連線"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index c304c14..d680b66 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Ngeke ize ixhumeke ngokuzenzakalela"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Akukho ukufinyelela kwe-inthanethi"</string>
<string name="saved_network" msgid="7143698034077223645">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
+ <skip />
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ixhumeke ngokuzenzakalela nge-%1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Kuxhunywe ngokuzenzakalelayo ngomhlinzeki wesilinganiso wenethiwekhi"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Kuxhumeke nge-%1$s"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 6d7e86f..34da305 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -108,7 +108,7 @@
* - If it's the first time and needFirstTimeWarning, show the first time dialog.
* - If it's 4th time through 8th time, show the schedule suggestion notification.
*
- * @param enable true to disable battery saver.
+ * @param enable true to enable battery saver.
*
* @return true if the request succeeded.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 93a8df4..cd3d6a8 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -26,8 +26,7 @@
private String mPackageName;
private long mTimeStarted;
private StringBuilder mState;
- // This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO
- private boolean mSilenced;
+ private boolean mIsDisabled;
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
this.mCode = code;
@@ -58,16 +57,16 @@
return mTimeStarted;
}
- public void setSilenced(boolean silenced) {
- mSilenced = silenced;
+ public void setDisabled(boolean misDisabled) {
+ this.mIsDisabled = misDisabled;
}
- public boolean isSilenced() {
- return mSilenced;
+ public boolean isDisabled() {
+ return mIsDisabled;
}
@Override
public String toString() {
- return mState.append(mSilenced).append(")").toString();
+ return mState.append(mIsDisabled).append(")").toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 1036c99..d8ca639 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.appops;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
import android.Manifest;
@@ -45,6 +47,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -64,7 +67,8 @@
@SysUISingleton
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
AppOpsManager.OnOpActiveChangedInternalListener,
- AppOpsManager.OnOpNotedListener, Dumpable {
+ AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback,
+ Dumpable {
// This is the minimum time that we will keep AppOps that are noted on record. If multiple
// occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
@@ -77,8 +81,8 @@
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
private final LocationManager mLocationManager;
- // TODO ntmyren: remove t
private final PackageManager mPackageManager;
+ private final IndividualSensorPrivacyController mSensorPrivacyController;
// mLocationProviderPackages are cached and updated only occasionally
private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
@@ -91,6 +95,7 @@
private final PermissionFlagsCache mFlagsCache;
private boolean mListening;
private boolean mMicMuted;
+ private boolean mCameraDisabled;
@GuardedBy("mActiveItems")
private final List<AppOpItem> mActiveItems = new ArrayList<>();
@@ -118,6 +123,7 @@
DumpManager dumpManager,
PermissionFlagsCache cache,
AudioManager audioManager,
+ IndividualSensorPrivacyController sensorPrivacyController,
BroadcastDispatcher dispatcher
) {
mDispatcher = dispatcher;
@@ -129,7 +135,10 @@
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
mAudioManager = audioManager;
- mMicMuted = audioManager.isMicrophoneMute();
+ mSensorPrivacyController = sensorPrivacyController;
+ mMicMuted = audioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
mLocationManager = context.getSystemService(LocationManager.class);
mPackageManager = context.getPackageManager();
dumpManager.registerDumpable(TAG, this);
@@ -147,6 +156,12 @@
mAppOps.startWatchingActive(OPS, this);
mAppOps.startWatchingNoted(OPS, this);
mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
+ mSensorPrivacyController.addCallback(this);
+
+ mMicMuted = mAudioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
mAudioManager.getActiveRecordingConfigurations()));
mDispatcher.registerReceiverWithHandler(this,
@@ -156,6 +171,7 @@
mAppOps.stopWatchingActive(this);
mAppOps.stopWatchingNoted(this);
mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
+ mSensorPrivacyController.removeCallback(this);
mBGHandler.removeCallbacksAndMessages(null); // null removes all
mDispatcher.unregisterReceiver(this);
@@ -235,11 +251,13 @@
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
if (code == AppOpsManager.OP_RECORD_AUDIO) {
- item.setSilenced(isAnyRecordingPausedLocked(uid));
+ item.setDisabled(isAnyRecordingPausedLocked(uid));
+ } else if (code == AppOpsManager.OP_CAMERA) {
+ item.setDisabled(mCameraDisabled);
}
mActiveItems.add(item);
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
- return !item.isSilenced();
+ return !item.isDisabled();
} else if (item != null && !active) {
mActiveItems.remove(item);
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
@@ -409,7 +427,7 @@
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item) && !item.isSilenced()) {
+ && isUserVisible(item) && !item.isDisabled()) {
list.add(item);
}
}
@@ -512,22 +530,27 @@
return false;
}
- private void updateRecordingPausedStatus() {
+ private void updateSensorDisabledStatus() {
synchronized (mActiveItems) {
int size = mActiveItems.size();
for (int i = 0; i < size; i++) {
AppOpItem item = mActiveItems.get(i);
+
+ boolean paused = false;
if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
- boolean paused = isAnyRecordingPausedLocked(item.getUid());
- if (item.isSilenced() != paused) {
- item.setSilenced(paused);
- notifySuscribers(
- item.getCode(),
- item.getUid(),
- item.getPackageName(),
- !item.isSilenced()
- );
- }
+ paused = isAnyRecordingPausedLocked(item.getUid());
+ } else if (item.getCode() == AppOpsManager.OP_CAMERA) {
+ paused = mCameraDisabled;
+ }
+
+ if (item.isDisabled() != paused) {
+ item.setDisabled(paused);
+ notifySuscribers(
+ item.getCode(),
+ item.getUid(),
+ item.getPackageName(),
+ !item.isDisabled()
+ );
}
}
}
@@ -552,14 +575,27 @@
recordings.add(recording);
}
}
- updateRecordingPausedStatus();
+ updateSensorDisabledStatus();
}
};
@Override
public void onReceive(Context context, Intent intent) {
- mMicMuted = mAudioManager.isMicrophoneMute();
- updateRecordingPausedStatus();
+ mMicMuted = mAudioManager.isMicrophoneMute()
+ || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ updateSensorDisabledStatus();
+ }
+
+ @Override
+ public void onSensorBlockedChanged(int sensor, boolean blocked) {
+ mBGHandler.post(() -> {
+ if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
+ mCameraDisabled = blocked;
+ } else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
+ mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
+ }
+ updateSensorDisabledStatus();
+ });
}
protected class H extends Handler {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index c2c6790..9be3566 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -23,7 +23,6 @@
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
@@ -59,7 +58,6 @@
private final Executor mBgExecutor;
private final ImageExporter mImageExporter;
private final ImageTileSet mImageTileSet;
- private final LayoutInflater mLayoutInflater;
private ZonedDateTime mCaptureTime;
private UUID mRequestId;
@@ -81,7 +79,6 @@
mBgExecutor = bgExecutor;
mImageExporter = exporter;
mImageTileSet = new ImageTileSet();
- mLayoutInflater = mContext.getSystemService(LayoutInflater.class);
}
/**
@@ -114,7 +111,7 @@
mEdit.setOnClickListener(this::onClicked);
mShare.setOnClickListener(this::onClicked);
- mPreview.setImageDrawable(mImageTileSet.getDrawable());
+ //mPreview.setImageDrawable(mImageTileSet.getDrawable());
mConnection.start(this::startCapture);
}
@@ -242,6 +239,7 @@
if (mImageTileSet.isEmpty()) {
session.end(mCallback::onFinish);
} else {
+ mPreview.setImageDrawable(mImageTileSet.getDrawable());
mExportFuture = mImageExporter.export(
mBgExecutor, mRequestId, mImageTileSet.toBitmap(), mCaptureTime);
// The user chose an action already, link it to the result
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d4a2b41..b20c457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2331,11 +2331,11 @@
&& mStatusBarWindowState != state) {
mStatusBarWindowState = state;
if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
- if (!showing && mState == StatusBarState.SHADE) {
- mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
if (mStatusBarView != null) {
+ if (!showing && mState == StatusBarState.SHADE) {
+ mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
+ 1.0f /* speedUpFactor */);
+ }
mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
updateHideIconsForBouncer(false /* animate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 231fe08..32d15ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.policy;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.IndividualSensor;
@@ -30,7 +30,8 @@
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
- private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
+ private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
+ INDIVIDUAL_SENSOR_MICROPHONE};
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
private final SparseBooleanArray mState = new SparseBooleanArray();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 02143a7..bc322f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.appops;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
+import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
@@ -49,6 +52,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import org.junit.Before;
import org.junit.Test;
@@ -81,6 +85,8 @@
private PermissionFlagsCache mFlagsCache;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private IndividualSensorPrivacyController mSensorPrivacyController;
@Mock(stubOnly = true)
private AudioManager mAudioManager;
@Mock()
@@ -118,12 +124,18 @@
when(mAudioManager.getActiveRecordingConfigurations())
.thenReturn(List.of(mPausedMockRecording));
+ when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ .thenReturn(false);
+ when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ .thenReturn(false);
+
mController = new AppOpsControllerImpl(
mContext,
mTestableLooper.getLooper(),
mDumpManager,
mFlagsCache,
mAudioManager,
+ mSensorPrivacyController,
mDispatcher
);
}
@@ -133,6 +145,7 @@
mController.setListening(true);
verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any());
+ verify(mSensorPrivacyController, times(1)).addCallback(mController);
}
@Test
@@ -140,6 +153,7 @@
mController.setListening(false);
verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
verify(mDispatcher, times(1)).unregisterReceiver(mController);
+ verify(mSensorPrivacyController, times(1)).removeCallback(mController);
}
@Test
@@ -476,6 +490,71 @@
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
}
+ @Test
+ public void testAudioFilteredWhenMicDisabled() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add a camera op, and disable the microphone. The camera op should be the only op returned
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+
+
+ // Re enable the microphone, and verify the op returns
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0;
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(micIdx).getCode());
+ }
+
+ @Test
+ public void testCameraFilteredWhenCameraDisabled() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
+ mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+ assertFalse(list.get(0).isDisabled());
+
+ // Add an audio op, and disable the camera. The audio op should be the only op returned
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+ list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
+
+ // Re enable the camera, and verify the op returns
+ mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, false);
+ mTestableLooper.processAllMessages();
+
+ list = mController.getActiveAppOps();
+ assertEquals(2, list.size());
+ int cameraIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 0 : 1;
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(cameraIdx).getCode());
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
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 1a63dde..8253927 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
@@ -218,7 +218,7 @@
@Override // Binder call
public void enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
- final int[] disabledFeatures, Surface surface) {
+ final int[] disabledFeatures, Surface surface, boolean debugConsent) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -229,7 +229,7 @@
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
receiver, opPackageName, disabledFeatures,
- convertSurfaceToNativeHandle(surface));
+ convertSurfaceToNativeHandle(surface), debugConsent);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 32428ac1..cc24b89 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -94,7 +94,8 @@
void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName,
- @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle);
+ @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle,
+ boolean debugConsent);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 211d79c..d2673d2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -142,7 +142,8 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), new int[0] /* disabledFeatures */, null /* surface */);
+ mContext.getOpPackageName(), new int[0] /* disabledFeatures */, null /* surface */,
+ false /* debugConsent */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index d60bb79..afc7f64 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -23,6 +23,7 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.face.EnrollmentType;
+import android.hardware.biometrics.face.Feature;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
@@ -55,12 +56,14 @@
@Nullable private ICancellationSignal mCancellationSignal;
@Nullable private android.hardware.common.NativeHandle mPreviewSurface;
private final int mMaxTemplatesPerUser;
+ private final boolean mDebugConsent;
FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String opPackageName,
@NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
- @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) {
+ @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser,
+ boolean debugConsent) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
false /* shouldVibrate */);
@@ -69,6 +72,7 @@
mEnrollIgnoreListVendor = getContext().getResources()
.getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
mMaxTemplatesPerUser = maxTemplatesPerUser;
+ mDebugConsent = debugConsent;
try {
// We must manually close the duplicate handle after it's no longer needed.
// The caller is responsible for closing the original handle.
@@ -116,9 +120,17 @@
try {
// TODO(b/172593978): Pass features.
// TODO(b/174619156): Handle accessibility enrollment.
+ byte[] features;
+ if (mDebugConsent) {
+ features = new byte[1];
+ features[0] = Feature.DEBUG;
+ } else {
+ features = new byte[0];
+ }
+
mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken),
- EnrollmentType.DEFAULT, new byte[0], mPreviewSurface);
+ EnrollmentType.DEFAULT, features, mPreviewSurface);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index f7feffd..e685ee2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -382,7 +382,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable NativeHandle previewSurface) {
+ @Nullable NativeHandle previewSurface, boolean debugConsent) {
mHandler.post(() -> {
final IFace daemon = getHalInstance();
if (daemon == null) {
@@ -404,7 +404,8 @@
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
- ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser);
+ ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
+ debugConsent);
scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index 9ed8f78..4142a52 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -131,7 +131,7 @@
mFace10.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
- null /* surfaceHandle */);
+ null /* surfaceHandle */, false /* debugConsent */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 775d8d4..e46661a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -602,7 +602,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable NativeHandle surfaceHandle) {
+ @Nullable NativeHandle surfaceHandle, boolean debugConsent) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d9ee9a3..13dc0b9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -710,9 +710,9 @@
}
}
- private void initialize() {
+ private void initialize(int displayState) {
mPowerState = new DisplayPowerState(mBlanker,
- mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId);
+ mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId, displayState);
if (mColorFadeEnabled) {
mColorFadeOnAnimator = ObjectAnimator.ofFloat(
@@ -812,11 +812,6 @@
mustNotify = !mDisplayReadyLocked;
}
- // Initialize things the first time the power state is changed.
- if (mustInitialize) {
- initialize();
- }
-
// Compute the basic display state using the policy.
// We might override this below based on other factors.
// Initialise brightness as invalid.
@@ -850,6 +845,11 @@
}
assert(state != Display.STATE_UNKNOWN);
+ // Initialize things the first time the power state is changed.
+ if (mustInitialize) {
+ initialize(state);
+ }
+
// Apply the proximity sensor.
if (mProximitySensor != null) {
if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 54f30a9..173adce 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -72,7 +72,8 @@
private Runnable mCleanListener;
- public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, int displayId) {
+ DisplayPowerState(
+ DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
@@ -81,14 +82,14 @@
mPhotonicModulator.start();
mDisplayId = displayId;
- // At boot time, we know that the screen is on and the electron beam
- // animation is not playing. We don't know the screen's brightness though,
+ // At boot time, we don't know the screen's brightness,
// so prepare to set it to a known state when the state is next applied.
- // Although we set the brightness to full on here, the display power controller
+ // Although we set the brightness here, the display power controller
// will reset the brightness to a new level immediately before the changes
// actually have a chance to be applied.
- mScreenState = Display.STATE_ON;
- mScreenBrightness = PowerManager.BRIGHTNESS_MAX;
+ mScreenState = displayState;
+ mScreenBrightness = (displayState != Display.STATE_OFF) ? PowerManager.BRIGHTNESS_MAX
+ : PowerManager.BRIGHTNESS_OFF_FLOAT;
scheduleScreenUpdate();
mColorFadePrepared = false;
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 5b3db01..5f7d938 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -63,7 +63,7 @@
@Override
public FontConfig getFontConfig() throws RemoteException {
- return getCurrentFontSettings().getSystemFontConfig();
+ return getSystemFontConfig();
}
/* package */ static class SystemFontException extends AndroidException {
@@ -103,7 +103,7 @@
if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
return null;
}
- return mService.getCurrentFontSettings().getSerializedSystemFontMap();
+ return mService.getCurrentFontMap();
}
});
publishBinderService(Context.FONT_SERVICE, mService);
@@ -162,7 +162,7 @@
@GuardedBy("FontManagerService.this")
@Nullable
- private SystemFontSettings mCurrentFontSettings = null;
+ private SharedMemory mSerializedFontMap = null;
private FontManagerService(Context context) {
mContext = context;
@@ -188,12 +188,12 @@
return mContext;
}
- @NonNull /* package */ SystemFontSettings getCurrentFontSettings() {
+ @NonNull /* package */ SharedMemory getCurrentFontMap() {
synchronized (FontManagerService.this) {
- if (mCurrentFontSettings == null) {
- mCurrentFontSettings = SystemFontSettings.create(mUpdatableFontDir);
+ if (mSerializedFontMap == null) {
+ mSerializedFontMap = buildNewSerializedFontMap();
}
- return mCurrentFontSettings;
+ return mSerializedFontMap;
}
}
@@ -207,7 +207,7 @@
synchronized (FontManagerService.this) {
mUpdatableFontDir.installFontFile(fd, pkcs7Signature);
// Create updated font map in the next getSerializedSystemFontMap() call.
- mCurrentFontSettings = null;
+ mSerializedFontMap = null;
}
}
@@ -245,69 +245,44 @@
new FontManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
}
- /* package */ static class SystemFontSettings {
- private final @NonNull SharedMemory mSerializedSystemFontMap;
- private final @NonNull FontConfig mSystemFontConfig;
- private final @NonNull Map<String, FontFamily[]> mSystemFallbackMap;
- private final @NonNull Map<String, Typeface> mSystemTypefaceMap;
+ /**
+ * Returns an active system font configuration.
+ */
+ public @NonNull FontConfig getSystemFontConfig() {
+ if (mUpdatableFontDir != null) {
+ return mUpdatableFontDir.getSystemFontConfig();
+ } else {
+ return SystemFonts.getSystemPreinstalledFontConfig();
+ }
+ }
- SystemFontSettings(
- @NonNull SharedMemory serializedSystemFontMap,
- @NonNull FontConfig systemFontConfig,
- @NonNull Map<String, FontFamily[]> systemFallbackMap,
- @NonNull Map<String, Typeface> systemTypefaceMap) {
- mSerializedSystemFontMap = serializedSystemFontMap;
- mSystemFontConfig = systemFontConfig;
- mSystemFallbackMap = systemFallbackMap;
- mSystemTypefaceMap = systemTypefaceMap;
+ /**
+ * Make new serialized font map data.
+ */
+ public @Nullable SharedMemory buildNewSerializedFontMap() {
+ try {
+ final FontConfig fontConfig = getSystemFontConfig();
+ final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
+ final Map<String, Typeface> typefaceMap =
+ SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+
+ return Typeface.serializeFontMap(typefaceMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.w(TAG, "Failed to serialize updatable font map. "
+ + "Retrying with system image fonts.", e);
}
- public @NonNull SharedMemory getSerializedSystemFontMap() {
- return mSerializedSystemFontMap;
- }
-
- public @NonNull FontConfig getSystemFontConfig() {
- return mSystemFontConfig;
- }
-
- public @NonNull Map<String, FontFamily[]> getSystemFallbackMap() {
- return mSystemFallbackMap;
- }
-
- public @NonNull Map<String, Typeface> getSystemTypefaceMap() {
- return mSystemTypefaceMap;
- }
-
- public static @Nullable SystemFontSettings create(
- @Nullable UpdatableFontDir updatableFontDir) {
- if (updatableFontDir != null) {
- final FontConfig fontConfig = updatableFontDir.getSystemFontConfig();
- final Map<String, FontFamily[]> fallback =
- SystemFonts.buildSystemFallback(fontConfig);
- final Map<String, Typeface> typefaceMap =
- SystemFonts.buildSystemTypefaces(fontConfig, fallback);
-
- try {
- final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
- return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
- } catch (IOException | ErrnoException e) {
- Slog.w(TAG, "Failed to serialize updatable font map. "
- + "Retrying with system image fonts.", e);
- }
- }
-
+ try {
final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
final Map<String, Typeface> typefaceMap =
SystemFonts.buildSystemTypefaces(fontConfig, fallback);
- try {
- final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
- return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
- } catch (IOException | ErrnoException e) {
- Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
- }
- return null;
+
+ return Typeface.serializeFontMap(typefaceMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
}
+ return null;
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
index fd5c020..5a01a97 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -25,6 +25,7 @@
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontManager;
import android.graphics.fonts.FontVariationAxis;
+import android.graphics.fonts.SystemFonts;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -95,8 +96,8 @@
}
/* package */ void dumpAll(@NonNull IndentingPrintWriter w) {
- final FontManagerService.SystemFontSettings settings = mService.getCurrentFontSettings();
- dumpFontConfig(w, settings.getSystemFontConfig());
+ FontConfig fontConfig = mService.getSystemFontConfig();
+ dumpFontConfig(w, fontConfig);
}
private void dumpSingleFontConfig(
@@ -276,19 +277,19 @@
private int dump(ShellCommand shell) {
final Context ctx = mService.getContext();
- final FontManagerService.SystemFontSettings settings =
- mService.getCurrentFontSettings();
+
if (!DumpUtils.checkDumpPermission(ctx, TAG, shell.getErrPrintWriter())) {
return 1;
}
final IndentingPrintWriter writer =
new IndentingPrintWriter(shell.getOutPrintWriter(), " ");
String nextArg = shell.getNextArg();
+ FontConfig fontConfig = mService.getSystemFontConfig();
if (nextArg == null) {
- dumpFontConfig(writer, settings.getSystemFontConfig());
+ dumpFontConfig(writer, fontConfig);
} else {
final Map<String, FontFamily[]> fallbackMap =
- settings.getSystemFallbackMap();
+ SystemFonts.buildSystemFallback(fontConfig);
FontFamily[] families = fallbackMap.get(nextArg);
if (families == null) {
writer.println("Font Family \"" + nextArg + "\" not found");
@@ -364,10 +365,9 @@
}
private int status(ShellCommand shell) throws SystemFontException {
- final FontManagerService.SystemFontSettings settings = mService.getCurrentFontSettings();
final IndentingPrintWriter writer =
new IndentingPrintWriter(shell.getOutPrintWriter(), " ");
- FontConfig config = settings.getSystemFontConfig();
+ FontConfig config = mService.getSystemFontConfig();
writer.println("Current Version: " + config.getConfigVersion());
LocalDateTime dt = LocalDateTime.ofEpochSecond(config.getLastModifiedDate(), 0,
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index b5b93d6..142f64f 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -74,7 +74,6 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
@@ -1297,10 +1296,7 @@
return null;
}
- long currentNanos = SystemClock.elapsedRealtimeNanos();
- long deltaMs = NANOSECONDS.toMillis(
- location.getElapsedRealtimeAgeNanos(currentNanos));
- return new LocationTime(location.getTime() + deltaMs, currentNanos);
+ return new LocationTime(location.getTime(), location.getElapsedRealtimeNanos());
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e218dc1..4eaac2e4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -70,7 +70,6 @@
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstallerSession;
import android.content.pm.IPackageInstallerSessionFileSystemConnector;
-import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.InstallationFile;
import android.content.pm.InstallationFileParcel;
import android.content.pm.PackageInfo;
@@ -322,8 +321,6 @@
private float mProgress = 0;
@GuardedBy("mLock")
private float mReportedProgress = -1;
- @GuardedBy("mLock")
- private float mIncrementalProgress = 0;
/** State of the session. */
@GuardedBy("mLock")
@@ -1202,12 +1199,7 @@
@GuardedBy("mLock")
private void computeProgressLocked(boolean forcePublish) {
- // This method is triggered when the client progress is updated or the incremental progress
- // is updated. For incremental installs, ignore the progress values reported from client.
- // Instead, only use the progress reported by IncFs as the percentage of loading completion.
- final float loadingProgress =
- isIncrementalInstallation() ? mIncrementalProgress : mClientProgress;
- mProgress = MathUtils.constrain(loadingProgress * 0.8f, 0f, 0.8f)
+ mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+ MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
// Only publish when meaningful change
@@ -3767,16 +3759,7 @@
try {
mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
params, statusListener, healthCheckParams, healthListener, addedFiles,
- perUidReadTimeouts,
- new IPackageLoadingProgressCallback.Stub() {
- @Override
- public void onPackageLoadingProgressChanged(float progress) {
- synchronized (mLock) {
- mIncrementalProgress = progress;
- computeProgressLocked(true);
- }
- }
- });
+ perUidReadTimeouts);
return false;
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c27e670..d2fc5b4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2153,6 +2153,10 @@
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
+ SigningDetails getSigningDetails(@NonNull String packageName);
+ SigningDetails getSigningDetails(int uid);
+ boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
+ boolean filterAppAccess(String packageName, int callingUid, int userId);
}
/**
@@ -4578,6 +4582,40 @@
throw new SecurityException(errorMessage);
}
+ public SigningDetails getSigningDetails(@NonNull String packageName) {
+ AndroidPackage p = mPackages.get(packageName);
+ if (p == null) {
+ return null;
+ }
+ return p.getSigningDetails();
+ }
+
+ public SigningDetails getSigningDetails(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ return ((SharedUserSetting) obj).signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return ps.signatures.mSigningDetails;
+ }
+ }
+ return SigningDetails.UNKNOWN;
+ }
+
+ public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ PackageSetting ps = getPackageSetting(pkg.getPackageName());
+ return shouldFilterApplicationLocked(ps, callingUid,
+ userId);
+ }
+
+ public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ PackageSetting ps = getPackageSetting(packageName);
+ return shouldFilterApplicationLocked(ps, callingUid,
+ userId);
+ }
+
}
/**
@@ -4728,6 +4766,26 @@
return super.getPackageUidInternal(packageName, flags, userId, callingUid);
}
}
+ public SigningDetails getSigningDetails(@NonNull String packageName) {
+ synchronized (mLock) {
+ return super.getSigningDetails(packageName);
+ }
+ }
+ public SigningDetails getSigningDetails(int uid) {
+ synchronized (mLock) {
+ return super.getSigningDetails(uid);
+ }
+ }
+ public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ synchronized (mLock) {
+ return super.filterAppAccess(pkg, callingUid, userId);
+ }
+ }
+ public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ synchronized (mLock) {
+ return super.filterAppAccess(packageName, callingUid, userId);
+ }
+ }
}
@@ -26560,6 +26618,22 @@
return snapshotComputer().getPackage(uid);
}
+ private SigningDetails getSigningDetails(@NonNull String packageName) {
+ return snapshotComputer().getSigningDetails(packageName);
+ }
+
+ private SigningDetails getSigningDetails(int uid) {
+ return snapshotComputer().getSigningDetails(uid);
+ }
+
+ private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ return snapshotComputer().filterAppAccess(pkg, callingUid, userId);
+ }
+
+ private boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ return snapshotComputer().filterAppAccess(packageName, callingUid, userId);
+ }
+
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
@@ -26615,29 +26689,11 @@
}
private SigningDetails getSigningDetails(@NonNull String packageName) {
- synchronized (mLock) {
- AndroidPackage p = mPackages.get(packageName);
- if (p == null) {
- return null;
- }
- return p.getSigningDetails();
- }
+ return PackageManagerService.this.getSigningDetails(packageName);
}
private SigningDetails getSigningDetails(int uid) {
- synchronized (mLock) {
- final int appId = UserHandle.getAppId(uid);
- final Object obj = mSettings.getSettingLPr(appId);
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- return ((SharedUserSetting) obj).signatures.mSigningDetails;
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- return ps.signatures.mSigningDetails;
- }
- }
- return SigningDetails.UNKNOWN;
- }
+ return PackageManagerService.this.getSigningDetails(uid);
}
@Override
@@ -26652,20 +26708,12 @@
@Override
public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- synchronized (mLock) {
- PackageSetting ps = getPackageSetting(pkg.getPackageName());
- return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
- userId);
- }
+ return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId);
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- synchronized (mLock) {
- PackageSetting ps = getPackageSetting(packageName);
- return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
- userId);
- }
+ return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId);
}
@Override
@@ -28304,6 +28352,13 @@
}
continue;
}
+ if (ps.appId < Process.FIRST_APPLICATION_UID) {
+ if (DEBUG_PER_UID_READ_TIMEOUTS) {
+ Slog.i(TAG, "PerUidReadTimeouts: package is system, appId=" + ps.appId);
+ }
+ continue;
+ }
+
final AndroidPackage pkg = ps.getPkg();
if (pkg.getLongVersionCode() < perPackage.versionCodes.minVersionCode
|| pkg.getLongVersionCode() > perPackage.versionCodes.maxVersionCode) {
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 8c31d88..aff87111 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3356,11 +3356,12 @@
// - or its signing certificate was rotated from the source package's certificate
// - or its signing certificate is a previous signing certificate of the defining
// package, and the defining package still trusts the old certificate for permissions
+ // - or it shares a common signing certificate in its lineage with the defining package,
+ // and the defining package still trusts the old certificate for permissions
// - or it shares the above relationships with the system package
final PackageParser.SigningDetails sourceSigningDetails =
getSourcePackageSigningDetails(bp);
- return pkg.getSigningDetails().hasAncestorOrSelf(sourceSigningDetails)
- || sourceSigningDetails.checkCapability(
+ return sourceSigningDetails.hasCommonSignerWithCapability(
pkg.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)
|| pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c073b43..89e7986 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3491,15 +3491,27 @@
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ final int keyCode = event.getKeyCode();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
+ || event.isWakeKey();
+
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
+ // Exception: Wake and power key events are forwarded to PowerManager to allow it to
+ // wake from quiescent mode during boot.
+ if (down && (keyCode == KeyEvent.KEYCODE_POWER
+ || keyCode == KeyEvent.KEYCODE_TV_POWER)) {
+ wakeUpFromPowerKey(event.getDownTime());
+ } else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)
+ && isWakeKeyWhenScreenOff(keyCode)) {
+ wakeUpFromWakeKey(event);
+ }
return 0;
}
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
- final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
- final int keyCode = event.getKeyCode();
final int displayId = event.getDisplayId();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -3518,8 +3530,6 @@
// Basic policy based on interactive state.
int result;
- boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
- || event.isWakeKey();
if (interactive || (isInjected && !isWakeKey)) {
// When the device is interactive or the key is injected pass the
// key to the application.
@@ -4740,7 +4750,7 @@
}
startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
- screenTurningOn(DEFAULT_DISPLAY, null);
+ screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
screenTurnedOn(DEFAULT_DISPLAY);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 54d0512..db4b6d0 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1036,12 +1036,12 @@
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+ updatePowerStateLocked();
if (sQuiescent) {
goToSleepNoUpdateLocked(mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
}
- updatePowerStateLocked();
}
}
}
@@ -1679,8 +1679,15 @@
Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
- if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE
- || mForceSuspendActive || !mSystemReady) {
+ if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
+ return false;
+ }
+
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
+ if (!mBootCompleted && sQuiescent) {
+ mDirty |= DIRTY_QUIESCENT;
+ return true;
+ }
return false;
}
@@ -2821,7 +2828,7 @@
*
* This function recalculates the display power state each time.
*
- * @return True if the display became ready.
+ * @return true if the display became ready.
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
@@ -2830,7 +2837,11 @@
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
DIRTY_QUIESCENT)) != 0) {
if ((dirty & DIRTY_QUIESCENT) != 0) {
- sQuiescent = false;
+ if (mDisplayReady) {
+ sQuiescent = false;
+ } else {
+ mDirty |= DIRTY_QUIESCENT;
+ }
}
final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
@@ -5605,7 +5616,7 @@
* ignore the proximity sensor. We don't turn off the proximity sensor because
* we still want it to be reenabled if it's state changes.
*
- * @return True if the proximity sensor was successfully ignored and we should
+ * @return true if the proximity sensor was successfully ignored and we should
* consume the key event.
*/
private boolean interceptPowerKeyDownInternal(KeyEvent event) {
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index 43f8a3a..57e39b6 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -21,6 +21,9 @@
import static android.service.rotationresolver.RotationResolverService.ROTATION_RESULT_FAILURE_CANCELLED;
import static android.service.rotationresolver.RotationResolverService.ROTATION_RESULT_FAILURE_TIMED_OUT;
+import static com.android.server.rotationresolver.RotationResolverManagerService.RESOLUTION_FAILURE;
+import static com.android.server.rotationresolver.RotationResolverManagerService.logRotationStats;
+
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
@@ -29,6 +32,7 @@
import android.os.Handler;
import android.os.ICancellationSignal;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.rotationresolver.RotationResolverInternal;
import android.service.rotationresolver.IRotationResolverCallback;
import android.service.rotationresolver.IRotationResolverService;
@@ -112,6 +116,7 @@
boolean mIsDispatched;
private final Object mLock = new Object();
+ private final long mRequestStartTimeMillis;
RotationRequest(
@NonNull RotationResolverInternal.RotationResolverCallbackInternal
@@ -125,6 +130,7 @@
mPackageName = packageName;
mIRotationResolverCallback = new RotationResolverCallback();
mCancellationSignalInternal = cancellationSignal;
+ mRequestStartTimeMillis = SystemClock.elapsedRealtime();
}
@@ -164,7 +170,10 @@
}
mIsFulfilled = true;
mCallbackInternal.onSuccess(rotation);
- logStats(rotation);
+ final long timeToCalculate =
+ SystemClock.elapsedRealtime() - mRequestStartTimeMillis;
+ logRotationStats(mProposedRotation, mCurrentRotation, rotation,
+ timeToCalculate);
}
}
@@ -177,7 +186,10 @@
}
mIsFulfilled = true;
mCallbackInternal.onFailure(error);
- logStats(error);
+ final long timeToCalculate =
+ SystemClock.elapsedRealtime() - mRequestStartTimeMillis;
+ logRotationStats(mProposedRotation, mCurrentRotation, RESOLUTION_FAILURE,
+ timeToCalculate);
}
}
@@ -196,10 +208,6 @@
}
}
-
- private void logStats(int result) {
- // TODO FrameworkStatsLog
- }
}
}
}
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
index f0e2d79..8a1c778 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
@@ -18,7 +18,9 @@
import static android.service.rotationresolver.RotationResolverService.ROTATION_RESULT_FAILURE_CANCELLED;
+import static com.android.server.rotationresolver.RotationResolverManagerService.RESOLUTION_UNAVAILABLE;
import static com.android.server.rotationresolver.RotationResolverManagerService.getServiceConfigPackage;
+import static com.android.server.rotationresolver.RotationResolverManagerService.logRotationStats;
import android.Manifest;
import android.annotation.NonNull;
@@ -98,6 +100,7 @@
if (!isServiceAvailableLocked()) {
Slog.w(TAG, "Service is not available at this moment.");
callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
+ logRotationStats(proposedRotation, currentRotation, RESOLUTION_UNAVAILABLE);
return;
}
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
index 0377d23..4a37e79 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
@@ -19,6 +19,11 @@
import static android.provider.DeviceConfig.NAMESPACE_ROTATION_RESOLVER;
import static android.service.rotationresolver.RotationResolverService.ROTATION_RESULT_FAILURE_CANCELLED;
+import static com.android.internal.util.FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_0;
+import static com.android.internal.util.FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_180;
+import static com.android.internal.util.FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_270;
+import static com.android.internal.util.FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_90;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -33,9 +38,11 @@
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Slog;
+import android.view.Surface;
import com.android.internal.R;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.SystemService;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -61,6 +68,15 @@
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = false;
+ static final int ORIENTATION_UNKNOWN =
+ FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__UNKNOWN;
+ static final int RESOLUTION_DISABLED =
+ FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__DISABLED;
+ static final int RESOLUTION_UNAVAILABLE =
+ FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__UNAVAILABLE;
+ static final int RESOLUTION_FAILURE =
+ FrameworkStatsLog.AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__FAILURE;
+
private final Context mContext;
boolean mIsServiceEnabled;
@@ -147,6 +163,7 @@
} else {
Slog.w(TAG, "Rotation Resolver service is disabled.");
callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
+ logRotationStats(proposedRotation, currentRotation, RESOLUTION_DISABLED);
}
}
}
@@ -178,4 +195,36 @@
resultReceiver);
}
}
+
+ static void logRotationStats(int proposedRotation, int currentRotation,
+ int resolvedRotation, long timeToCalculate) {
+ FrameworkStatsLog.write(FrameworkStatsLog.AUTO_ROTATE_REPORTED,
+ /* previous_orientation= */ surfaceRotationToProto(currentRotation),
+ /* proposed_orientation= */ surfaceRotationToProto(proposedRotation),
+ /* resolved_orientation= */ surfaceRotationToProto(resolvedRotation),
+ /* process_duration_millis= */ timeToCalculate);
+ }
+
+ static void logRotationStats(int proposedRotation, int currentRotation,
+ int resolvedRotation) {
+ FrameworkStatsLog.write(FrameworkStatsLog.AUTO_ROTATE_REPORTED,
+ /* previous_orientation= */ surfaceRotationToProto(currentRotation),
+ /* proposed_orientation= */ surfaceRotationToProto(proposedRotation),
+ /* resolved_orientation= */ surfaceRotationToProto(resolvedRotation));
+ }
+
+ private static int surfaceRotationToProto(@Surface.Rotation int rotationPoseResult) {
+ switch (rotationPoseResult) {
+ case Surface.ROTATION_0:
+ return AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_0;
+ case Surface.ROTATION_90:
+ return AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_90;
+ case Surface.ROTATION_180:
+ return AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_180;
+ case Surface.ROTATION_270:
+ return AUTO_ROTATE_REPORTED__PROPOSED_ORIENTATION__ROTATION_270;
+ default:
+ return ORIENTATION_UNKNOWN;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 509cbde..3bb4c74 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1355,11 +1355,13 @@
final boolean surfaceReady = w.isDrawn() // Regular case
|| w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready.
|| w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
- final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
+ final boolean needsLetterbox = surfaceReady && isLetterboxed(w);
+ updateRoundedCorners(w);
if (needsLetterbox) {
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> makeChildSurface(null),
- mWmService.mTransactionFactory);
+ mWmService.mTransactionFactory,
+ mWmService::isLetterboxActivityCornersRounded);
mLetterbox.attachInput(w);
}
getPosition(mTmpPoint);
@@ -1371,7 +1373,7 @@
final Rect spaceToFill = transformedBounds != null
? transformedBounds
: inMultiWindowMode()
- ? task.getBounds()
+ ? getRootTask().getBounds()
: getRootTask().getParent().getBounds();
mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
} else if (mLetterbox != null) {
@@ -1379,6 +1381,27 @@
}
}
+ /** @return {@code true} when main window is letterboxed and activity isn't transparent. */
+ private boolean isLetterboxed(WindowState mainWindow) {
+ return mainWindow.isLetterboxedAppWindow() && fillsParent();
+ }
+
+ private void updateRoundedCorners(WindowState mainWindow) {
+ int cornersRadius =
+ // Don't round corners if letterboxed only for display cutout.
+ isLetterboxed(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout()
+ ? Math.max(0, mWmService.getLetterboxActivityCornersRadius()) : 0;
+ setCornersRadius(mainWindow, cornersRadius);
+ }
+
+ private void setCornersRadius(WindowState mainWindow, int cornersRadius) {
+ final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
+ if (windowSurface != null && windowSurface.isValid()) {
+ Transaction transaction = getPendingTransaction();
+ transaction.setCornerRadius(windowSurface, cornersRadius);
+ }
+ }
+
void updateLetterboxSurface(WindowState winHint) {
final WindowState w = findMainWindow();
if (w != winHint && winHint != null && w != null) {
@@ -1408,10 +1431,14 @@
}
/**
- * @see Letterbox#notIntersectsOrFullyContains(Rect)
+ * @return {@code true} if bar shown within a given rectangle is allowed to be transparent
+ * when the current activity is displayed.
*/
- boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
- return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
+ boolean isTransparentBarAllowed(Rect rect) {
+ // TODO(b/175482966): Allow status and navigation bars to be semi-transparent black
+ // in letterbox mode.
+ return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect)
+ || mWmService.isLetterboxActivityCornersRounded();
}
/**
@@ -6589,8 +6616,7 @@
// which point, the activity type is still undefined if it will be standard.
// For other non-standard types, the type is set in the constructor, so this should
// not be a problem.
- && isActivityTypeStandardOrUndefined()
- && !mAtmService.mForceResizableActivities;
+ && isActivityTypeStandardOrUndefined();
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0db3f9..404773d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -35,6 +35,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1877,6 +1878,12 @@
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
+ if (isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ Slog.w(TAG, "setTaskWindowingMode: Is in lock task mode="
+ + getLockTaskModeState());
+ return false;
+ }
+
if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
return setTaskWindowingModeSplitScreen(taskId, windowingMode, toTop);
}
@@ -2141,11 +2148,6 @@
throw new IllegalArgumentException("Calling setTaskWindowingModeSplitScreen with non"
+ "split-screen mode: " + windowingMode);
}
- if (isInLockTaskMode()) {
- Slog.w(TAG, "setTaskWindowingModeSplitScreen: Is in lock task mode="
- + getLockTaskModeState());
- return false;
- }
final Task task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_ONLY);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 4a90bbc..eee27c7 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -56,6 +56,6 @@
if (win == null) {
return true;
}
- return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win));
+ return win.isTransparentBarAllowed(getContentFrame(win));
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2a40500..0aaa1a1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -190,6 +190,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
+import android.view.DisplayCutout.CutoutPathParserInfo;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
@@ -1934,18 +1935,22 @@
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return WmDisplayCutout.NO_CUTOUT;
}
- final Insets waterfallInsets =
- RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
return WmDisplayCutout.computeSafeInsets(
cutout, mInitialDisplayWidth, mInitialDisplayHeight);
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final Rect[] newBounds = mRotationUtil.getRotatedBounds(
cutout.getBoundingRectsAll(),
rotation, mInitialDisplayWidth, mInitialDisplayHeight);
+ final CutoutPathParserInfo info = cutout.getCutoutPathParserInfo();
+ final CutoutPathParserInfo newInfo = new CutoutPathParserInfo(
+ info.getDisplayWidth(), info.getDisplayHeight(), info.getDensity(),
+ info.getCutoutSpec(), rotation, info.getScale());
return WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
+ DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo),
rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
}
@@ -3604,7 +3609,7 @@
&& mImeLayeringTarget.mActivityRecord.matchParentBounds()
// IME is attached to non-Letterboxed app windows, other than windows with
// LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER flag. (Refer to WS.isLetterboxedAppWindow())
- && mImeLayeringTarget.matchesRootDisplayAreaBounds();
+ && mImeLayeringTarget.matchesDisplayAreaBounds();
}
/**
@@ -4102,8 +4107,15 @@
* Callbacks when the given type of {@link WindowContainer} animation finished running in the
* hierarchy.
*/
- void onWindowAnimationFinished(int type) {
+ void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
+ // Unfreeze the insets state of the frozen target when the animation finished if exists.
+ final Task task = wc.asTask();
+ if (task != null) {
+ task.forAllWindows(w -> {
+ w.clearFrozenInsetsState();
+ }, true /* traverseTopToBottom */);
+ }
removeImeSurfaceImmediately();
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 398049f..267f677 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -74,7 +74,7 @@
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
- if (w.isVisible()) {
+ if (w.isReadyToDispatchInsetsState()) {
w.notifyInsetsChanged();
}
};
@@ -117,7 +117,8 @@
final @InternalInsetsType int type = provider != null
? provider.getSource().getType() : ITYPE_INVALID;
return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
- isAboveIme(target));
+ isAboveIme(target),
+ target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() : mState);
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -132,7 +133,7 @@
final @WindowingMode int windowingMode = token != null
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
- return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token));
+ return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token), mState);
}
private boolean isAboveIme(WindowContainer target) {
@@ -180,9 +181,8 @@
* @see #getInsetsForWindowMetrics
*/
private InsetsState getInsetsForTarget(@InternalInsetsType int type,
- @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
- InsetsState state = mState;
-
+ @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme,
+ @NonNull InsetsState state) {
if (type != ITYPE_INVALID) {
state = new InsetsState(state);
state.removeSource(type);
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 44ce4de..02a43b7 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -44,12 +44,17 @@
private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
+ private final Supplier<Boolean> mAreCornersRounded;
private final Rect mOuter = new Rect();
private final Rect mInner = new Rect();
private final LetterboxSurface mTop = new LetterboxSurface("top");
private final LetterboxSurface mLeft = new LetterboxSurface("left");
private final LetterboxSurface mBottom = new LetterboxSurface("bottom");
private final LetterboxSurface mRight = new LetterboxSurface("right");
+ // Prevents wallpaper from peeking through near rounded corners. It's not included in
+ // mSurfaces array since it isn't needed in methods like notIntersectsOrFullyContains
+ // or attachInput.
+ private final LetterboxSurface mBehind = new LetterboxSurface("behind");
private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
/**
@@ -58,9 +63,11 @@
* @param surfaceControlFactory a factory for creating the managed {@link SurfaceControl}s
*/
public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory,
- Supplier<SurfaceControl.Transaction> transactionFactory) {
+ Supplier<SurfaceControl.Transaction> transactionFactory,
+ Supplier<Boolean> areCornersRounded) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
+ mAreCornersRounded = areCornersRounded;
}
/**
@@ -82,6 +89,7 @@
mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin);
mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin);
+ mBehind.layout(inner.left, inner.top, inner.right, inner.bottom, surfaceOrigin);
}
@@ -157,6 +165,7 @@
for (LetterboxSurface surface : mSurfaces) {
surface.remove();
}
+ mBehind.remove();
}
/** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */
@@ -166,6 +175,9 @@
return true;
}
}
+ if (mBehind.needsApplySurfaceChanges()) {
+ return true;
+ }
return false;
}
@@ -173,6 +185,11 @@
for (LetterboxSurface surface : mSurfaces) {
surface.applySurfaceChanges(t);
}
+ if (mAreCornersRounded.get()) {
+ mBehind.applySurfaceChanges(t);
+ } else {
+ mBehind.remove();
+ }
}
/** Enables touches to slide into other neighboring surfaces. */
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ec1588d..6a3110f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -35,6 +35,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -2859,41 +2860,61 @@
adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
if (windowingMode == WINDOWING_MODE_FREEFORM) {
- // by policy, make sure the window remains within parent somewhere
- final float density =
- ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
- final Rect parentBounds =
- new Rect(newParentConfig.windowConfiguration.getBounds());
- final DisplayContent display = getDisplayContent();
- if (display != null) {
- // If a freeform window moves below system bar, there is no way to move it again
- // by touch. Because its caption is covered by system bar. So we exclude them
- // from root task bounds. and then caption will be shown inside stable area.
- final Rect stableBounds = new Rect();
- display.getStableRect(stableBounds);
- parentBounds.intersect(stableBounds);
- }
+ computeFreeformBounds(outOverrideBounds, newParentConfig);
+ return;
+ }
- fitWithinBounds(outOverrideBounds, parentBounds,
- (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
- (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+ if (isSplitScreenWindowingMode(windowingMode)
+ || windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ // This is to compute whether the task should be letterboxed to handle non-resizable app
+ // in multi window. There is no split screen only logic.
+ computeLetterboxBounds(outOverrideBounds, newParentConfig);
+ }
+ }
- // Prevent to overlap caption with stable insets.
- final int offsetTop = parentBounds.top - outOverrideBounds.top;
- if (offsetTop > 0) {
- outOverrideBounds.offset(0, offsetTop);
- }
+ /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. */
+ @VisibleForTesting
+ void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
+ // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
+ outBounds.setEmpty();
+ computeLetterboxBounds(outBounds, newParentConfig);
+ }
+
+ /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
+ private void computeFreeformBounds(@NonNull Rect outBounds,
+ @NonNull Configuration newParentConfig) {
+ // by policy, make sure the window remains within parent somewhere
+ final float density =
+ ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
+ final Rect parentBounds =
+ new Rect(newParentConfig.windowConfiguration.getBounds());
+ final DisplayContent display = getDisplayContent();
+ if (display != null) {
+ // If a freeform window moves below system bar, there is no way to move it again
+ // by touch. Because its caption is covered by system bar. So we exclude them
+ // from root task bounds. and then caption will be shown inside stable area.
+ final Rect stableBounds = new Rect();
+ display.getStableRect(stableBounds);
+ parentBounds.intersect(stableBounds);
+ }
+
+ fitWithinBounds(outBounds, parentBounds,
+ (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
+ (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+
+ // Prevent to overlap caption with stable insets.
+ final int offsetTop = parentBounds.top - outBounds.top;
+ if (offsetTop > 0) {
+ outBounds.offset(0, offsetTop);
}
}
/**
- * Compute bounds (letterbox or pillarbox) for
- * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
- * orientation change and the requested orientation is different from the parent.
+ * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
+ * change and the requested orientation is different from the parent.
*/
- void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
- // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
- outBounds.setEmpty();
+ private void computeLetterboxBounds(@NonNull Rect outBounds,
+ @NonNull Configuration newParentConfig) {
if (handlesOrientationChangeFromDescendant()) {
// No need to letterbox at task level. Display will handle fixed-orientation requests.
return;
@@ -2951,6 +2972,8 @@
aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
? letterboxAspectRatioOverride : aspect;
+ // Store the current bounds to be able to revert to size compat mode values below if needed.
+ mTmpFullBounds.set(outBounds);
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
final int height = (int) Math.rint(parentWidth / aspect);
final int top = parentBounds.centerY() - height / 2;
@@ -2969,7 +2992,7 @@
// The app shouldn't be resized, we only do task letterboxing if the compat bounds
// is also from the same task letterbox. Otherwise, clear the task bounds to show
// app in size compat mode.
- outBounds.setEmpty();
+ outBounds.set(mTmpFullBounds);
}
}
}
@@ -3355,8 +3378,9 @@
@Override
boolean handlesOrientationChangeFromDescendant() {
return super.handlesOrientationChangeFromDescendant()
- // Display won't rotate for the orientation request if the TaskDisplayArea can't
- // specify orientation.
+ // Display won't rotate for the orientation request if the Task/TaskDisplayArea
+ // can't specify orientation.
+ && canSpecifyOrientation()
&& getDisplayArea().canSpecifyOrientation();
}
@@ -3869,7 +3893,9 @@
}
boolean isTaskLetterboxed() {
- return getWindowingMode() == WINDOWING_MODE_FULLSCREEN && !matchParentBounds();
+ // No letterbox for multi window root task
+ return !matchParentBounds()
+ && (getWindowingMode() == WINDOWING_MODE_FULLSCREEN || !isRootTask());
}
@Override
@@ -6041,7 +6067,9 @@
mInResumeTopActivity = true;
if (isLeafTask()) {
- someActivityResumed = resumeTopActivityInnerLocked(prev, options);
+ if (isFocusableAndVisible()) {
+ someActivityResumed = resumeTopActivityInnerLocked(prev, options);
+ }
} else {
int idx = mChildren.size() - 1;
while (idx >= 0) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 03fca11..dd4ee877 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2684,6 +2684,14 @@
@Nullable ArrayList<WindowContainer> sources) {
final Task task = asTask();
if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
+ if (AppTransition.isClosingTransitOld(transit)) {
+ // Freezes the insets state when the window is in app exiting transition, to
+ // ensure the exiting window won't receive unexpected insets changes from the
+ // next window.
+ task.forAllWindows(w -> {
+ w.freezeInsetsState();
+ }, true /* traverseTopToBottom */);
+ }
mDisplayContent.showImeScreenshot();
}
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
@@ -2831,7 +2839,7 @@
}
mSurfaceAnimationSources.clear();
if (mDisplayContent != null) {
- mDisplayContent.onWindowAnimationFinished(type);
+ mDisplayContent.onWindowAnimationFinished(this, type);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b6fabee3..8e6a778 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1012,6 +1012,9 @@
// ignored.
private float mTaskLetterboxAspectRatio;
+ // Corners radius for activities presented in the letterbox mode, values < 0 will be ignored.
+ private int mLetterboxActivityCornersRadius;
+
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
@@ -1239,6 +1242,8 @@
com.android.internal.R.bool.config_assistantOnTopOfDream);
mTaskLetterboxAspectRatio = context.getResources().getFloat(
com.android.internal.R.dimen.config_taskLetterboxAspectRatio);
+ mLetterboxActivityCornersRadius = context.getResources().getInteger(
+ com.android.internal.R.integer.config_letterboxActivityCornersRadius);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -3936,6 +3941,60 @@
}
}
+ /**
+ * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+ * both it and a value of {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
+ * and corners of the activity won't be rounded.
+ */
+ void setLetterboxActivityCornersRadius(int cornersRadius) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ mLetterboxActivityCornersRadius = cornersRadius;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Resets corners raidus for activities presented in the letterbox mode to {@link
+ * com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
+ */
+ void resetLetterboxActivityCornersRadius() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_letterboxActivityCornersRadius);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Whether corners of letterboxed activities are rounded.
+ */
+ boolean isLetterboxActivityCornersRounded() {
+ return getLetterboxActivityCornersRadius() > 0;
+ }
+
+ /**
+ * Gets corners raidus for activities presented in the letterbox mode.
+ */
+ int getLetterboxActivityCornersRadius() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ return mLetterboxActivityCornersRadius;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
@Override
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
mAtmInternal.enforceCallerIsRecentsOrHasPermission(
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a3a9c1c..badd29a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -115,6 +115,10 @@
return runSetTaskLetterboxAspectRatio(pw);
case "get-task-letterbox-aspect-ratio":
return runGetTaskLetterboxAspectRatio(pw);
+ case "set-letterbox-activity-corners-radius":
+ return runSetLetterboxActivityCornersRadius(pw);
+ case "get-letterbox-activity-corners-radius":
+ return runGetLetterboxActivityCornersRadius(pw);
case "reset":
return runReset(pw);
default:
@@ -545,6 +549,38 @@
return 0;
}
+ private int runSetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
+ final int cornersRadius;
+ try {
+ String arg = getNextArgRequired();
+ if ("reset".equals(arg)) {
+ mInternal.resetLetterboxActivityCornersRadius();
+ return 0;
+ }
+ cornersRadius = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad corners radius format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'reset' or corners radius should be provided as an argument " + e);
+ return -1;
+ }
+
+ mInternal.setLetterboxActivityCornersRadius(cornersRadius);
+ return 0;
+ }
+
+ private int runGetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
+ final int cornersRadius = mInternal.getLetterboxActivityCornersRadius();
+ if (cornersRadius < 0) {
+ pw.println("Letterbox corners radius is not set");
+ } else {
+ pw.println("Letterbox corners radius is " + cornersRadius);
+ }
+ return 0;
+ }
+
private int runReset(PrintWriter pw) throws RemoteException {
int displayId = getDisplayId(getNextArg());
@@ -572,6 +608,9 @@
// set-task-letterbox-aspect-ratio
mInternal.resetTaskLetterboxAspectRatio();
+ // set-letterbox-activity-corners-radius
+ mInternal.resetLetterboxActivityCornersRadius();
+
pw.println("Reset all settings for displayId=" + displayId);
return 0;
}
@@ -608,6 +647,11 @@
+ WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO);
pw.println(" both it and R.dimen.config_taskLetterboxAspectRatio will be ignored");
pw.println(" and framework implementation will be used to determine aspect ratio.");
+ pw.println(" set-letterbox-activity-corners-radius [reset|cornersRadius]");
+ pw.println(" get-letterbox-activity-corners-radius");
+ pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
+ pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be");
+ pw.println(" ignored and corners of the activity won't be rounded.");
pw.println(" reset [-d DISPLAY_ID]");
pw.println(" Reset all override settings.");
if (!IS_USER) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 043844b..1b81914 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
@@ -264,57 +265,63 @@
}
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
- for (int i = 0, n = hops.size(); i < n; ++i) {
- final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
- switch (hop.getType()) {
- case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
- if (task != null) {
- task.getDisplayArea().setLaunchRootTask(task,
- hop.getWindowingModes(), hop.getActivityTypes());
- } else {
- throw new IllegalArgumentException(
- "Cannot set non-task as launch root: " + wc);
+ if (!hops.isEmpty() && mService.isInLockTaskMode()) {
+ Slog.w(TAG, "Attempt to perform hierarchy operations while in lock task mode...");
+ } else {
+ for (int i = 0, n = hops.size(); i < n; ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+ switch (hop.getType()) {
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
+ final WindowContainer wc = WindowContainer.fromBinder(
+ hop.getContainer());
+ final Task task = wc != null ? wc.asTask() : null;
+ if (task != null) {
+ task.getDisplayArea().setLaunchRootTask(task,
+ hop.getWindowingModes(), hop.getActivityTypes());
+ } else {
+ throw new IllegalArgumentException(
+ "Cannot set non-task as launch root: " + wc);
+ }
+ break;
}
- break;
- }
- case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
- effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
- break;
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
- effects |= setAdjacentRootsHierarchyOp(hop);
- break;
- case HIERARCHY_OP_TYPE_REORDER:
- case HIERARCHY_OP_TYPE_REPARENT:
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- if (wc == null || !wc.isAttached()) {
- Slog.e(TAG, "Attempt to operate on detached container: " + wc);
- continue;
- }
- if (syncId >= 0) {
- addToSyncSet(syncId, wc);
- }
- if (transition != null) {
- transition.collect(wc);
- if (hop.isReparent()) {
- if (wc.getParent() != null) {
- // Collect the current parent. It's visibility may change as
- // a result of this reparenting.
- transition.collect(wc.getParent());
- }
- if (hop.getNewParent() != null) {
- final WindowContainer parentWc =
- WindowContainer.fromBinder(hop.getNewParent());
- if (parentWc == null) {
- Slog.e(TAG, "Can't resolve parent window from token");
- continue;
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
+ break;
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
+ effects |= setAdjacentRootsHierarchyOp(hop);
+ break;
+ case HIERARCHY_OP_TYPE_REORDER:
+ case HIERARCHY_OP_TYPE_REPARENT:
+ final WindowContainer wc = WindowContainer.fromBinder(
+ hop.getContainer());
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on detached container: " + wc);
+ continue;
+ }
+ if (syncId >= 0) {
+ addToSyncSet(syncId, wc);
+ }
+ if (transition != null) {
+ transition.collect(wc);
+ if (hop.isReparent()) {
+ if (wc.getParent() != null) {
+ // Collect the current parent. It's visibility may change as
+ // a result of this reparenting.
+ transition.collect(wc.getParent());
}
- transition.collect(parentWc);
+ if (hop.getNewParent() != null) {
+ final WindowContainer parentWc =
+ WindowContainer.fromBinder(hop.getNewParent());
+ if (parentWc == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ continue;
+ }
+ transition.collect(parentWc);
+ }
}
}
- }
- effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ }
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -412,6 +419,10 @@
}
if (windowingMode > -1) {
+ if (mService.isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ throw new UnsupportedOperationException("Not supported to set non-fullscreen"
+ + " windowing mode during locked task mode.");
+ }
container.setWindowingMode(windowingMode);
}
return effects;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 093106f..9a7823e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -713,6 +713,12 @@
private @Nullable InsetsSourceProvider mControllableInsetProvider;
private final InsetsState mRequestedInsetsState = new InsetsState();
+ /**
+ * Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
+ * (e.g app exiting transition)
+ */
+ private InsetsState mFrozenInsetsState;
+
@Nullable InsetsSourceProvider mPendingPositionChanged;
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
@@ -758,6 +764,33 @@
}
}
+ /**
+ * Set a freeze state for the window to ignore dispatching its insets state to the client.
+ *
+ * Used to keep the insets state for some use cases. (e.g. app exiting transition)
+ */
+ void freezeInsetsState() {
+ if (mFrozenInsetsState == null) {
+ mFrozenInsetsState = new InsetsState(getInsetsState(), true /* copySources */);
+ }
+ }
+
+ void clearFrozenInsetsState() {
+ mFrozenInsetsState = null;
+ }
+
+ InsetsState getFrozenInsetsState() {
+ return mFrozenInsetsState;
+ }
+
+ /**
+ * Check if the insets state of the window is ready to dispatch to the client when invoking
+ * {@link InsetsStateController#notifyInsetsChanged}.
+ */
+ boolean isReadyToDispatchInsetsState() {
+ return isVisible() && mFrozenInsetsState == null;
+ }
+
void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
@Rotation int rotation, boolean requested) {
// Invisible windows and the wallpaper do not participate in the seamless rotation animation
@@ -2110,12 +2143,12 @@
return getDisplayContent().getBounds().equals(getBounds());
}
- boolean matchesRootDisplayAreaBounds() {
- RootDisplayArea root = getRootDisplayArea();
- if (root == null || root == getDisplayContent()) {
+ boolean matchesDisplayAreaBounds() {
+ final DisplayArea displayArea = getDisplayArea();
+ if (displayArea == null) {
return matchesDisplayBounds();
}
- return root.getBounds().equals(getBounds());
+ return displayArea.getBounds().equals(getBounds());
}
/**
@@ -3762,16 +3795,20 @@
return getDisplayContent().mCurrentFocus == this;
}
-
/** Is this window in a container that takes up the entire screen space? */
private boolean inAppWindowThatMatchesParentBounds() {
return mActivityRecord == null || (mActivityRecord.matchParentBounds() && !inMultiWindowMode());
}
- /** @return true when the window is in fullscreen mode, but has non-fullscreen bounds set, or
- * is transitioning into/out-of fullscreen. */
+ /** @return true when the window should be letterboxed. */
boolean isLetterboxedAppWindow() {
- return !inMultiWindowMode() && !matchesRootDisplayAreaBounds()
+ // Fullscreen mode but doesn't fill display area.
+ return (!inMultiWindowMode() && !matchesDisplayAreaBounds())
+ // Activity in size compat.
+ || (mActivityRecord != null && mActivityRecord.inSizeCompatMode())
+ // Task letterboxed.
+ || (getTask() != null && getTask().isTaskLetterboxed())
+ // Letterboxed for display cutout.
|| isLetterboxedForDisplayCutout();
}
@@ -3809,11 +3846,11 @@
}
/**
- * @see Letterbox#notIntersectsOrFullyContains(Rect)
+ * @return {@code true} if bar shown within a given frame is allowed to be transparent
+ * when the current window is displayed.
*/
- boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
- return mActivityRecord == null
- || mActivityRecord.letterboxNotIntersectsOrFullyContains(rect);
+ boolean isTransparentBarAllowed(Rect frame) {
+ return mActivityRecord == null || mActivityRecord.isTransparentBarAllowed(frame);
}
public boolean isLetterboxedOverlappingWith(Rect rect) {
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 6fabc58..dfa6083 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -210,7 +210,17 @@
ErrorCode setUidReadTimeouts(const Control& control,
const std::vector<android::os::incremental::PerUidReadTimeouts>&
perUidReadTimeouts) const final {
- return -ENOTSUP;
+ std::vector<incfs::UidReadTimeouts> timeouts;
+ timeouts.resize(perUidReadTimeouts.size());
+ for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
+ auto&& timeout = timeouts[i];
+ const auto& perUidTimeout = perUidReadTimeouts[i];
+ timeout.uid = perUidTimeout.uid;
+ timeout.minTimeUs = perUidTimeout.minTimeUs;
+ timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
+ timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
+ }
+ return incfs::setUidReadTimeouts(control, timeouts);
}
};
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 091e688..5453de1 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -45,7 +45,6 @@
import com.android.server.SystemService;
import com.android.server.people.data.DataManager;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -156,6 +155,13 @@
final IBinder mService = new IPeopleManager.Stub() {
@Override
+ public ConversationChannel getConversation(
+ String packageName, int userId, String shortcutId) {
+ enforceSystemRootOrSystemUI(getContext(), "get conversation");
+ return mDataManager.getConversation(packageName, userId, shortcutId);
+ }
+
+ @Override
public ParceledListSlice<ConversationChannel> getRecentConversations() {
enforceSystemRootOrSystemUI(getContext(), "get recent conversations");
return new ParceledListSlice<>(
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 7521415..9a9a171 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -222,33 +222,65 @@
mContext.getPackageName(), intentFilter, callingUserId);
}
+ /**
+ * Returns a {@link ConversationChannel} with the associated {@code shortcutId} if existent.
+ * Otherwise, returns null.
+ */
+ @Nullable
+ public ConversationChannel getConversation(String packageName, int userId, String shortcutId) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData != null) {
+ PackageData packageData = userData.getPackageData(packageName);
+ // App may have been uninstalled.
+ if (packageData != null) {
+ return getConversationChannel(packageData, shortcutId);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private ConversationChannel getConversationChannel(PackageData packageData, String shortcutId) {
+ ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+ if (conversationInfo == null) {
+ return null;
+ }
+ int userId = packageData.getUserId();
+ String packageName = packageData.getPackageName();
+ ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
+ if (shortcutInfo == null) {
+ return null;
+ }
+ int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
+ NotificationChannel parentChannel =
+ mNotificationManagerInternal.getNotificationChannel(packageName, uid,
+ conversationInfo.getParentNotificationChannelId());
+ NotificationChannelGroup parentChannelGroup = null;
+ if (parentChannel != null) {
+ parentChannelGroup =
+ mNotificationManagerInternal.getNotificationChannelGroup(packageName,
+ uid, parentChannel.getId());
+ }
+ return new ConversationChannel(shortcutInfo, uid, parentChannel,
+ parentChannelGroup,
+ conversationInfo.getLastEventTimestamp(),
+ hasActiveNotifications(packageName, userId, shortcutId));
+ }
+
/** Returns the cached non-customized recent conversations. */
public List<ConversationChannel> getRecentConversations(@UserIdInt int callingUserId) {
List<ConversationChannel> conversationChannels = new ArrayList<>();
forPackagesInProfile(callingUserId, packageData -> {
- String packageName = packageData.getPackageName();
- int userId = packageData.getUserId();
packageData.forAllConversations(conversationInfo -> {
if (!isCachedRecentConversation(conversationInfo)) {
return;
}
String shortcutId = conversationInfo.getShortcutId();
- ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
- int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
- NotificationChannel parentChannel =
- mNotificationManagerInternal.getNotificationChannel(packageName, uid,
- conversationInfo.getParentNotificationChannelId());
- if (shortcutInfo == null || parentChannel == null) {
+ ConversationChannel channel = getConversationChannel(packageData, shortcutId);
+ if (channel == null || channel.getParentNotificationChannel() == null) {
return;
}
- NotificationChannelGroup parentChannelGroup =
- mNotificationManagerInternal.getNotificationChannelGroup(packageName,
- uid, parentChannel.getId());
- conversationChannels.add(
- new ConversationChannel(shortcutInfo, uid, parentChannel,
- parentChannelGroup,
- conversationInfo.getLastEventTimestamp(),
- hasActiveNotifications(packageName, userId, shortcutId)));
+ conversationChannels.add(channel);
});
});
return conversationChannels;
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 63330d5..161d316 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -515,6 +515,85 @@
}
@Test
+ public void testGetConversationReturnsCustomizedConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ }
+
+ @Test
+ public void testGetConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNotNull();
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID + "1")).isNull();
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertThat(result).isNotNull();
+ assertEquals(shortcut.getId(), result.getShortcutInfo().getId());
+ assertEquals(1, result.getShortcutInfo().getPersons().length);
+ assertEquals(CONTACT_URI, result.getShortcutInfo().getPersons()[0].getUri());
+ assertEquals(mParentNotificationChannel.getId(),
+ result.getParentNotificationChannel().getId());
+ assertEquals(mStatusBarNotification.getPostTime(), result.getLastEventTimestamp());
+ assertTrue(result.hasActiveNotifications());
+ }
+
+ @Test
+ public void testGetConversationGetsPersonsData() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+
+ verify(mShortcutServiceInternal).getShortcuts(
+ anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+ mQueryFlagsCaptor.capture(), anyInt(), anyInt(), anyInt());
+ Integer queryFlags = mQueryFlagsCaptor.getValue();
+ assertThat(hasFlag(queryFlags, ShortcutQuery.FLAG_GET_PERSONS_DATA)).isTrue();
+ }
+
+ @Test
public void testNotificationChannelCreated() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
mDataManager.onUserUnlocked(USER_ID_SECONDARY);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 533dc17..1d0b595 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -877,6 +877,22 @@
}
@Test
+ public void testQuiescentBoot_WakeKeyBeforeBootCompleted_AwakeAfterBootCompleted()
+ throws Exception {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ mService.systemReady(null);
+
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
+
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ DisplayPowerRequest.POLICY_BRIGHT);
+ }
+
+ @Test
public void testIsAmbientDisplayAvailable_available() throws Exception {
createService();
when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
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 83282a5..4bea9a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -27,7 +27,6 @@
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
-import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -96,6 +95,7 @@
import android.app.WindowConfiguration;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.metrics.LogMaker;
@@ -558,7 +558,7 @@
// hence isLetterboxedAppWindow() returns true.
ws.mActivityRecord.getConfiguration().windowConfiguration.setBounds(new Rect(1, 1, 1, 1));
assertFalse("matchesRootDisplayAreaBounds() should return false",
- ws.matchesRootDisplayAreaBounds());
+ ws.matchesDisplayAreaBounds());
assertTrue("isLetterboxedAppWindow() should return true", ws.isLetterboxedAppWindow());
assertTrue("IME shouldn't be attached to app",
dc.computeImeParent() != dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
@@ -707,6 +707,7 @@
// same width and height.
final int displayWidth = dc.mInitialDisplayWidth;
final int displayHeight = dc.mInitialDisplayHeight;
+ final float density = dc.mInitialDisplayDensity;
final int cutoutWidth = 40;
final int cutoutHeight = 10;
final int left = (displayWidth - cutoutWidth) / 2;
@@ -714,9 +715,13 @@
final int right = (displayWidth + cutoutWidth) / 2;
final int bottom = cutoutHeight;
- final Rect r1 = new Rect(left, top, right, bottom);
+ final Rect zeroRect = new Rect();
+ final Rect[] bounds = new Rect[]{zeroRect, new Rect(left, top, right, bottom), zeroRect,
+ zeroRect};
+ final DisplayCutout.CutoutPathParserInfo info = new DisplayCutout.CutoutPathParserInfo(
+ displayWidth, displayHeight, density, "", Surface.ROTATION_0, 1f);
final DisplayCutout cutout = new WmDisplayCutout(
- fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
+ DisplayCutout.constructDisplayCutout(bounds, Insets.NONE, info), null)
.computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
dc.mInitialDisplayCutout = cutout;
@@ -731,9 +736,12 @@
// | | ---o
// | | |
// | | -------------
- final Rect r = new Rect(top, left, bottom, right);
+ final Rect[] bounds90 = new Rect[]{new Rect(top, left, bottom, right), zeroRect, zeroRect,
+ zeroRect};
+ final DisplayCutout.CutoutPathParserInfo info90 = new DisplayCutout.CutoutPathParserInfo(
+ displayWidth, displayHeight, density, "", Surface.ROTATION_90, 1f);
assertEquals(new WmDisplayCutout(
- fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
+ DisplayCutout.constructDisplayCutout(bounds90, Insets.NONE, info90), null)
.computeSafeInsets(displayHeight, displayWidth).getDisplayCutout(),
dc.getDisplayInfo().displayCutout);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index 2f3004b..a045100 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -17,6 +17,9 @@
package com.android.server.wm;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
@@ -47,10 +50,12 @@
SurfaceControlMocker mSurfaces;
SurfaceControl.Transaction mTransaction;
+ private boolean mAreCornersRounded = false;
+
@Before
public void setUp() throws Exception {
mSurfaces = new SurfaceControlMocker();
- mLetterbox = new Letterbox(mSurfaces, StubTransaction::new);
+ mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, () -> mAreCornersRounded);
mTransaction = spy(StubTransaction.class);
}
@@ -64,6 +69,7 @@
private static final int BOTTOM_BAR = 0x2;
private static final int LEFT_BAR = 0x4;
private static final int RIGHT_BAR = 0x8;
+
@Test
public void testNotIntersectsOrFullyContains_usesGlobalCoordinates() {
final Rect outer = new Rect(0, 0, 10, 50);
@@ -165,6 +171,41 @@
}
@Test
+ public void testApplySurfaceChanges_cornersNotRounded_surfaceBehindNotCreated() {
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ assertNull(mSurfaces.behind);
+ }
+
+ @Test
+ public void testApplySurfaceChanges_cornersRounded_surfaceBehindCreated() {
+ mAreCornersRounded = true;
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ assertNotNull(mSurfaces.behind);
+ }
+
+ @Test
+ public void testIsOverlappingWith_cornersRounded_doesNotCheckSurfaceBehind() {
+ mAreCornersRounded = true;
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ assertFalse(mLetterbox.isOverlappingWith(new Rect(1, 2, 9, 9)));
+ }
+
+ @Test
+ public void testNotIntersectsOrFullyContains_cornersRounded_doesNotCheckSurfaceBehind() {
+ mAreCornersRounded = true;
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ assertTrue(mLetterbox.notIntersectsOrFullyContains(new Rect(1, 2, 9, 9)));
+ }
+
+ @Test
public void testSurfaceOrigin_changeCausesReapply() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
mLetterbox.applySurfaceChanges(mTransaction);
@@ -184,6 +225,8 @@
public SurfaceControl right;
private SurfaceControl.Builder mBottomBuilder;
public SurfaceControl bottom;
+ private SurfaceControl.Builder mBehindBuilder;
+ public SurfaceControl behind;
@Override
public SurfaceControl.Builder get() {
@@ -198,6 +241,8 @@
mRightBuilder = (SurfaceControl.Builder) i.getMock();
} else if (((String) i.getArgument(0)).contains("bottom")) {
mBottomBuilder = (SurfaceControl.Builder) i.getMock();
+ } else if (((String) i.getArgument(0)).contains("behind")) {
+ mBehindBuilder = (SurfaceControl.Builder) i.getMock();
}
return i.getMock();
});
@@ -212,6 +257,8 @@
right = control;
} else if (i.getMock() == mBottomBuilder) {
bottom = control;
+ } else if (i.getMock() == mBehindBuilder) {
+ behind = control;
}
return control;
}).when(builder).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 371e680..942e1c9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -16,15 +16,16 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
-import static android.view.SurfaceProto.ROTATION_180;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -35,6 +36,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.Task.ActivityState.STOPPED;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -905,6 +907,57 @@
assertEquals(1000, activityBounds.height());
}
+ @Test
+ public void testSupportsNonResizableInSplitScreen() {
+ // Support non resizable in multi window
+ mAtm.mSupportsNonResizableMultiWindow = true;
+ setUpDisplaySizeWithApp(1000, 2800);
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+
+ // Non-resizable landscape activity
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+
+ // Move activity to split screen
+ mTask.reparent(organizer.mPrimary, POSITION_TOP,
+ false /*moveParents*/, "test");
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, mActivity.getWindowingMode());
+
+ // Non-resizable activity in size compat mode
+ assertScaled();
+ assertEquals(originalBounds,
+ mActivity.getConfiguration().windowConfiguration.getBounds());
+
+ // Recompute the natural configuration of the non-resizable activity and the split screen.
+ mActivity.clearSizeCompatMode();
+
+ // Draw letterbox.
+ mActivity.setVisible(false);
+ mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
+ mActivity.mDisplayContent.mOpeningApps.add(mActivity);
+ addWindowToActivity(mActivity);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ // Split screen is also in portrait [1000,1400], so Task should be in letterbox, and
+ // activity fills task.
+ assertEquals(ORIENTATION_LANDSCAPE, mTask.getConfiguration().orientation);
+ assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
+ assertFitted();
+ assertTrue(mTask.isTaskLetterboxed());
+
+ // Letterbox should fill the gap between the split screen and the letterboxed task.
+ final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
+ final Rect letterboxedTaskBounds = new Rect(mTask.getBounds());
+ assertTrue(primarySplitBounds.contains(letterboxedTaskBounds));
+ assertEquals(new Rect(letterboxedTaskBounds.left - primarySplitBounds.left,
+ letterboxedTaskBounds.top - primarySplitBounds.top,
+ primarySplitBounds.right - letterboxedTaskBounds.right,
+ primarySplitBounds.bottom - letterboxedTaskBounds.bottom),
+ mActivity.getLetterboxInsets());
+ }
+
private static WindowState addWindowToActivity(ActivityRecord activity) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index b0b8afd..df5b48a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -22,6 +22,8 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
@@ -978,6 +980,31 @@
assertEquals(200, listener.mConfiguration.densityDpi);
}
+ @Test
+ public void testFreezeInsetsStateWhenAppTransition() {
+ final Task stack = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+ task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
+ spyOn(win);
+ doReturn(true).when(task).okToAnimate();
+ ArrayList<WindowContainer> sources = new ArrayList<>();
+ sources.add(activity);
+
+ // Simulate the task applying the exit transition, verify the main window of the task
+ // will be set the frozen insets state.
+ task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
+ false /* isVoiceInteraction */, sources);
+ verify(win).freezeInsetsState();
+
+ // Simulate the task transition finished, verify the frozen insets state of the window
+ // will be reset.
+ task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
+ task.mSurfaceAnimator.getAnimation());
+ verify(win).clearFrozenInsetsState();
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 263aa19..3231f8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -810,4 +810,27 @@
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
}
+
+ @Test
+ public void testSetFreezeInsetsState() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ spyOn(app);
+ doReturn(true).when(app).isVisible();
+
+ // Set freezing the insets state to make the window ignore to dispatch insets changed.
+ final InsetsState expectedState = new InsetsState(app.getInsetsState(),
+ true /* copySources */);
+ app.freezeInsetsState();
+ assertEquals(expectedState, app.getFrozenInsetsState());
+ assertFalse(app.isReadyToDispatchInsetsState());
+ assertEquals(expectedState, app.getInsetsState());
+ mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+ verify(app, never()).notifyInsetsChanged();
+
+ // Unfreeze the insets state to make the window can dispatch insets changed.
+ app.clearFrozenInsetsState();
+ assertTrue(app.isReadyToDispatchInsetsState());
+ mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+ verify(app).notifyInsetsChanged();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
index 39976a5..b2646f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
@@ -150,9 +150,9 @@
@Test
public void computeSafeInsets_waterfall() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(1, 2, 3, 4)),
+ Insets.of(1, 2, 3, 4), null),
200, 400);
assertEquals(new Rect(1, 2, 3, 4), cutout.getDisplayCutout().getSafeInsets());
@@ -161,9 +161,9 @@
@Test
public void computeSafeInsets_cutoutTop_greaterThan_waterfallTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
- Insets.of(0, 20, 0, 0)),
+ Insets.of(0, 20, 0, 0), null),
200, 400);
assertEquals(new Rect(0, 30, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -172,9 +172,9 @@
@Test
public void computeSafeInsets_cutoutTop_lessThan_waterfallTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
- Insets.of(0, 40, 0, 0)),
+ Insets.of(0, 40, 0, 0), null),
200, 400);
assertEquals(new Rect(0, 40, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -183,9 +183,9 @@
@Test
public void computeSafeInsets_cutoutLeft_greaterThan_waterfallLeft() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(20, 0, 0, 0)),
+ Insets.of(20, 0, 0, 0), null),
200, 400);
assertEquals(new Rect(30, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -194,9 +194,9 @@
@Test
public void computeSafeInsets_cutoutLeft_lessThan_waterfallLeft() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
- Insets.of(40, 0, 0, 0)),
+ Insets.of(40, 0, 0, 0), null),
200, 400);
assertEquals(new Rect(40, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -205,9 +205,9 @@
@Test
public void computeSafeInsets_cutoutBottom_greaterThan_waterfallBottom() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
- Insets.of(0, 0, 0, 20)),
+ Insets.of(0, 0, 0, 20), null),
200, 400);
assertEquals(new Rect(0, 0, 0, 30), cutout.getDisplayCutout().getSafeInsets());
@@ -216,9 +216,9 @@
@Test
public void computeSafeInsets_cutoutBottom_lessThan_waterfallBottom() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
- Insets.of(0, 0, 0, 40)),
+ Insets.of(0, 0, 0, 40), null),
200, 400);
assertEquals(new Rect(0, 0, 0, 40), cutout.getDisplayCutout().getSafeInsets());
@@ -227,9 +227,9 @@
@Test
public void computeSafeInsets_cutoutRight_greaterThan_waterfallRight() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
- Insets.of(0, 0, 20, 0)),
+ Insets.of(0, 0, 20, 0), null),
200, 400);
assertEquals(new Rect(0, 0, 30, 0), cutout.getDisplayCutout().getSafeInsets());
@@ -238,9 +238,9 @@
@Test
public void computeSafeInsets_cutoutRight_lessThan_waterfallRight() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- DisplayCutout.fromBoundsAndWaterfall(
+ DisplayCutout.constructDisplayCutout(
new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
- Insets.of(0, 0, 40, 0)),
+ Insets.of(0, 0, 40, 0), null),
200, 400);
assertEquals(new Rect(0, 0, 40, 0), cutout.getDisplayCutout().getSafeInsets());
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index b359ebe..fadf0e1 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -554,7 +554,8 @@
}
public @NonNull Builder setFrequencyRange(int frequencyRange) {
- if (!ServiceState.isFrequencyRangeValid(frequencyRange)) {
+ if (!ServiceState.isFrequencyRangeValid(frequencyRange)
+ && frequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
throw new IllegalArgumentException("Frequency range: " + frequencyRange +
" is invalid.");
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 59e375f..f474ec2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -114,7 +114,8 @@
enabled = !configuration.startRotation.isRotated())
navBarLayerIsAlwaysVisible()
statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE),
+ enabled = false)
imeLayerBecomesInvisible()
imeAppLayerBecomesInvisible(testApp)
diff --git a/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java b/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
index 24b1854..1d479fc 100644
--- a/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
+++ b/wifi/java/src/android/net/wifi/nl80211/SingleScanSettings.java
@@ -32,6 +32,7 @@
private static final String TAG = "SingleScanSettings";
public int scanType;
+ public boolean enable6GhzRnr;
public ArrayList<ChannelSettings> channelSettings;
public ArrayList<HiddenNetwork> hiddenNetworks;
@@ -50,6 +51,7 @@
return false;
}
return scanType == settings.scanType
+ && enable6GhzRnr == settings.enable6GhzRnr
&& channelSettings.equals(settings.channelSettings)
&& hiddenNetworks.equals(settings.hiddenNetworks);
}
@@ -57,7 +59,7 @@
/** override hash code */
@Override
public int hashCode() {
- return Objects.hash(scanType, channelSettings, hiddenNetworks);
+ return Objects.hash(scanType, channelSettings, hiddenNetworks, enable6GhzRnr);
}
@@ -83,6 +85,7 @@
Log.wtf(TAG, "Invalid scan type " + scanType);
}
out.writeInt(scanType);
+ out.writeBoolean(enable6GhzRnr);
out.writeTypedList(channelSettings);
out.writeTypedList(hiddenNetworks);
}
@@ -100,6 +103,7 @@
if (!isValidScanType(result.scanType)) {
Log.wtf(TAG, "Invalid scan type " + result.scanType);
}
+ result.enable6GhzRnr = in.readBoolean();
result.channelSettings = new ArrayList<ChannelSettings>();
in.readTypedList(result.channelSettings, ChannelSettings.CREATOR);
result.hiddenNetworks = new ArrayList<HiddenNetwork>();
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index db2eb99..ef26532 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -28,6 +28,7 @@
import android.net.wifi.WifiAnnotations;
import android.net.wifi.WifiScanner;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -90,6 +91,10 @@
*/
public static final int SCAN_TYPE_PNO_SCAN = 1;
+ // Extra scanning parameter used to enable 6Ghz RNR (Reduced Neighbour Support).
+ public static final String SCANNING_PARAM_ENABLE_6GHZ_RNR =
+ "android.net.wifi.nl80211.SCANNING_PARAM_ENABLE_6GHZ_RNR";
+
private AlarmManager mAlarmManager;
private Handler mEventHandler;
@@ -911,6 +916,15 @@
}
/**
+ * @deprecated replaced by {@link #startScan(String, int, Set, List, Bundle)}
+ **/
+ @Deprecated
+ public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
+ @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
+ return startScan(ifaceName, scanType, freqs, hiddenNetworkSSIDs, null);
+ }
+
+ /**
* Start a scan using the specified parameters. A scan is an asynchronous operation. The
* result of the operation is returned in the {@link ScanEventCallback} registered when
* setting up an interface using
@@ -929,11 +943,13 @@
* @param freqs list of frequencies to scan for, if null scan all supported channels.
* @param hiddenNetworkSSIDs List of hidden networks to be scanned for, a null indicates that
* no hidden frequencies will be scanned for.
+ * @param extraScanningParams bundle of extra scanning parameters.
* @return Returns true on success, false on failure (e.g. when called before the interface
* has been set up).
*/
public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
- @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
+ @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs,
+ @Nullable Bundle extraScanningParams) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
@@ -948,6 +964,9 @@
}
settings.channelSettings = new ArrayList<>();
settings.hiddenNetworks = new ArrayList<>();
+ if (extraScanningParams != null) {
+ settings.enable6GhzRnr = extraScanningParams.getBoolean(SCANNING_PARAM_ENABLE_6GHZ_RNR);
+ }
if (freqs != null) {
for (Integer freq : freqs) {
diff --git a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
index 9059208..fd595fa 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
@@ -74,6 +74,7 @@
new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
scanSettings.hiddenNetworks =
new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+ scanSettings.enable6GhzRnr = true;
Parcel parcel = Parcel.obtain();
scanSettings.writeToParcel(parcel, 0);
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
index 9ee0acbf..4b03a49 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
@@ -44,6 +44,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiScanner;
import android.net.wifi.util.HexEncoding;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -506,7 +507,51 @@
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ }
+
+ /**
+ * Verify the new startScan() API can convert input parameters to SingleScanSettings correctly.
+ */
+ @Test
+ public void testScanWithBundle() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR, true);
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, bundle));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, true)));
+ }
+
+ /**
+ * Verify default values in SingleScanSettings when the input Bundle to startScan is null.
+ */
+ @Test
+ public void testScanWithNullBundle() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, null));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
+ }
+
+ /**
+ * Verify default values in SingleScanSettings when the input Bundle to startScan is empty.
+ */
+ @Test
+ public void testScanWithEmptyBundle() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, new Bundle()));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
}
/**
@@ -527,7 +572,7 @@
// But the argument passed down should have the duplicate removed.
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
- SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST, false)));
}
/**
@@ -539,7 +584,7 @@
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
- IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null)));
+ IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null, false)));
}
/**
@@ -1068,11 +1113,14 @@
int mExpectedScanType;
private final Set<Integer> mExpectedFreqs;
private final List<byte[]> mExpectedSsids;
+ private final boolean mExpectedEnable6GhzRnr;
- ScanMatcher(int expectedScanType, Set<Integer> expectedFreqs, List<byte[]> expectedSsids) {
+ ScanMatcher(int expectedScanType, Set<Integer> expectedFreqs, List<byte[]> expectedSsids,
+ boolean expectedEnable6GhzRnr) {
this.mExpectedScanType = expectedScanType;
this.mExpectedFreqs = expectedFreqs;
this.mExpectedSsids = expectedSsids;
+ this.mExpectedEnable6GhzRnr = expectedEnable6GhzRnr;
}
@Override
@@ -1080,6 +1128,9 @@
if (settings.scanType != mExpectedScanType) {
return false;
}
+ if (settings.enable6GhzRnr != mExpectedEnable6GhzRnr) {
+ return false;
+ }
ArrayList<ChannelSettings> channelSettings = settings.channelSettings;
ArrayList<HiddenNetwork> hiddenNetworks = settings.hiddenNetworks;
if (mExpectedFreqs != null) {