diff options
187 files changed, 2399 insertions, 635 deletions
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 ed55f0056ea0..3bbc945c8b87 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 class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { } schemasPackageAccessible.put(entry.getKey(), packageIdentifiers); } - AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = + mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId); impl.setSchema( packageName, databaseName, @@ -133,7 +134,8 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { // 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 fe3c2e1d1604..97b1a8cd6d50 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 @@ import java.io.File; 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 @@ public final class ImplInstanceManager { * <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 @@ public final class ImplInstanceManager { * * @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 ec712d875323..3dd1f598f94f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -46182,6 +46182,7 @@ package android.view { 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 0f1296ee01fe..0a0f77e33ed4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7758,11 +7758,13 @@ package android.net.wifi.nl80211 { 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 c237d7d57238..ea7dc03c4007 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -684,6 +684,7 @@ package android.content.pm { 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 68d3a9203f12..49f508d83f91 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5255,6 +5255,7 @@ public class Notification implements Parcelable // 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 000000000000..78df2f10c337 --- /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 0d12ed02f610..ebe9f60dc150 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 @@ import android.os.IBinder; * {@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 68792b2f47de..9ae9c25c8c08 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3385,6 +3385,7 @@ public abstract class PackageManager { * {@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 fe8bf9d163c7..e6c0f6a4c2fa 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6265,6 +6265,55 @@ public class PackageParser { } /** + * 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 75893d978749..588bc01d7d42 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -301,7 +301,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan @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 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * 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 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan 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 1b188e87e90f..a3e7e2d2c5cb 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -74,7 +74,7 @@ interface IFaceService { // 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 9fdc72bbe6c6..59292baa110c 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -36,7 +36,6 @@ import android.annotation.Nullable; 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 @@ public final class IncrementalFileStorages { @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 @@ public final class IncrementalFileStorages { 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 @@ public final class IncrementalFileStorages { 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 b1b29254783c..8b6082b30dee 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -28,7 +28,10 @@ import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; 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.PackageManager; 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 @@ public class PermissionUsageHelper { 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 @@ public class PermissionUsageHelper { /** 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 @@ public class PermissionUsageHelper { ); private static final List<String> MIC_OPS = List.of( - OPSTR_PHONE_CALL_CAMERA, + OPSTR_PHONE_CALL_MICROPHONE, OPSTR_RECORD_AUDIO ); @@ -163,6 +179,13 @@ public class PermissionUsageHelper { 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 @@ public class PermissionUsageHelper { 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 @@ public class PermissionUsageHelper { 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 81b6f05a1658..733fca934c4e 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 a44ed59c14d4..698cb77947cf 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_180; 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 @@ public class RotationUtils { } 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 525ac534612d..e1a4402d8964 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_LEFT; 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.NonNull; 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 @@ public final class DisplayCutout { "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 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { @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 @@ public final class DisplayCutout { } return result; } + @Override public boolean equals(@Nullable Object o) { if (o == this) { @@ -232,6 +244,106 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { // 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 @@ public final class DisplayCutout { @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 @@ public final class DisplayCutout { // 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 @@ public final class DisplayCutout { * * @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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { return "DisplayCutout{insets=" + mSafeInsets + " waterfall=" + mWaterfallInsets + " boundingRect={" + mBounds + "}" + + " cutoutPathParserInfo={" + mCutoutPathParserInfo + "}" + "}"; } @@ -607,7 +796,7 @@ public final class DisplayCutout { } 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 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { * * @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 final class DisplayCutout { */ 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 @@ public final class DisplayCutout { * @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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 @@ public final class DisplayCutout { 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 106e3927656f..0a1a23116941 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -414,6 +414,15 @@ public final class SurfaceControl implements Parcelable { */ 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 0e878fcf0e24..4ef63ae93016 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -262,7 +262,7 @@ public: } } - 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 @@ public: 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 396f95446bf6..4a0a35de7c17 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 89407763a9b6..4f920dac1bcf 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 71b59e4d643f..5e0cda69911b 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 78a6e6232074..dfccdf4bd9a5 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 24f45a57dabc..bffd1e4a86d6 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.assertTrue; 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 androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest public class SigningDetailsTest { @@ -208,8 +211,8 @@ public class SigningDetailsTest { 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 @@ public class SigningDetailsTest { 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 @@ public class SigningDetailsTest { 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 @@ public class SigningDetailsTest { } 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 d02c6d588585..a5261aecdbfb 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 android.view.DisplayCutout.fromSpec; 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.assertThat; 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 @@ public class DisplayCutoutTest { @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 @@ public class DisplayCutoutTest { } @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 1df2a4a9030d..bb8a97344664 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, } 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 3181dbf74ace..58a4baf39614 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 @@ public class DisplayLayout { 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 @@ public class DisplayLayout { } 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 4874d3ccae7e..a4cd3c5a583d 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 @@ public class HandlerExecutor implements ShellExecutor { } @Override + public void removeAllCallbacks() { + mHandler.removeCallbacksAndMessages(null); + } + + @Override public void removeCallbacks(@NonNull Runnable r) { mHandler.removeCallbacks(r); } @@ -55,9 +60,4 @@ public class HandlerExecutor implements ShellExecutor { 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 1149cceb1068..b736fb0b9895 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 @@ public interface ShellExecutor extends Executor { 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 @@ public interface ShellExecutor extends Executor { * 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 d22abe4dd19b..125e322974bf 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.graphics.Rect; 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 @@ public class OneHandedAnimationController { 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 @@ public class OneHandedAnimationController { } @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 @@ public class OneHandedAnimationController { 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 @@ public class OneHandedAnimationController { ValueAnimator.AnimatorListener { private final SurfaceControl mLeash; + private final WindowContainerToken mToken; private T mStartValue; private T mEndValue; private T mCurrentValue; @@ -128,8 +130,10 @@ public class OneHandedAnimationController { 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 @@ public class OneHandedAnimationController { return this; } - SurfaceControl getLeash() { - return mLeash; + WindowContainerToken getToken() { + return mToken; } Rect getDestinationBounds() { @@ -254,10 +258,10 @@ public class OneHandedAnimationController { } @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 a74f4761af0c..37a91d0c121c 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 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer 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 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer @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 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer 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 d2d5591100d4..1da72f8efbb8 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.Point; 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 com.android.wm.shell.common.ShellExecutor; 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { final DisplayAreaAppearedInfo info = displayAreaInfos.get(i); onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash()); } + mDefaultDisplayBounds.set(getDisplayBounds()); return displayAreaInfos; } @@ -176,9 +162,9 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { * 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { : 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { .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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 1ed121f35a59..49b7e050c48b 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 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, 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 60709bef4daf..c7a49ff01d15 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 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback { 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 7a634c3eef78..6e3a20d5f2b2 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 @@ public class PipInputConsumer { // 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 41cc59d138fa..8fb358ad74d1 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 @@ public class PipResizeGestureHandler { // 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 c9f5ae28175c..2b8b53cdf285 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 @@ public class PipTouchHandler { 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 af99543199ac..224cc197bddd 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 @@ package com.android.wm.shell.flicker.legacysplitscreen 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 @@ class EnterLegacySplitScreenTest( } } + @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 785ccf003504..870adb8e1733 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 @@ package com.android.wm.shell.flicker.legacysplitscreen 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 @@ class RotateTwoLaunchedAppTest( } } + @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 5f5c30bb6207..bf84a6e30c98 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 @@ public class TestShellExecutor implements ShellExecutor { } @Override + public void removeAllCallbacks() { + mRunnables.clear(); + } + + @Override public void removeCallbacks(Runnable r) { mRunnables.remove(r); } @@ -49,11 +54,6 @@ public class TestShellExecutor implements ShellExecutor { 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 17fc0578dd2b..8d5139b182f0 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.graphics.Rect; 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 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase { @Mock private SurfaceControl mMockLeash; + @Mock + private WindowContainerToken mMockToken; @Mock private ShellExecutor mMainExecutor; @@ -69,7 +72,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase { 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 6cfd0c43724c..01162b5c0b83 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 com.google.common.truth.Truth.assertThat; 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 class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { 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 class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { 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 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { 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 9219f15afc7f..bbe8891817d6 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 android.testing.TestableLooper; 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 @@ import java.util.ArrayList; @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 @@ public class OneHandedTimeoutHandlerTest extends OneHandedTestCase { 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 6f4f72aae8ca..3837743a0ff8 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 3f5df34b07b0..4ce01d68a5ae 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 0351d946c05c..2580d0fc82cc 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 0f7db8f1e966..b61ff508cfe7 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 0855d17e8c70..d06377677a50 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 3386fe8649ea..2976bb5893b6 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 6ac2172496c4..7af9e9323e05 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 19ed5bdd5688..77b6493931f7 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 b0e9342c19c6..819625b67725 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 9377624d6d26..193ac6066e40 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 a2a7770e7db7..fef9bfb5c8c2 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 4db4d5c81e3f..281a78850e00 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 b76afa5c42d6..69cc8d805091 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 ba760dd54020..737ea167a8c9 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 c608a629a80d..8e1d5e3d1b18 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 e67c3d1ddc5a..b98c4b8968e9 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 b0830fc40e2e..aa0d3f1ddf18 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 e67c3d1ddc5a..b98c4b8968e9 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 e67c3d1ddc5a..b98c4b8968e9 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 4c0af75fada6..c01f3a05645e 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 9ae77819029b..f79072fff1e9 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 203726a5d557..f99a3f12307b 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 379ed6cb9065..fa2aa467d0c5 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 2582854924fe..2c4a8ee09f5e 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 cb598e523100..1c6ca763197a 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 31dfe1829133..04c9130ec31f 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 a8476dd212d1..aa0cd2a684c7 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 a79ed0c51ef7..dbdc160030fa 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 97662a65fafe..90c130301a8f 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 46bd71b9b382..4caeda279849 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 9cae3112cd48..468808be918a 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 83bb2d1e7732..932c2560f2d9 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 9f184c7052f5..fbaffac6b083 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 cd6cbf3bc396..224d6418b5d5 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 3b8091872562..8cf13cde6a42 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 ce9e66522aaf..aa8893e4783a 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 93b24a0bf066..0199f549d099 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 ab678092dd9c..a50a22d2d08d 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 711a22f8a41e..a1d1b70d607e 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 08133056c408..77fd4b156024 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 16ee9c00fa18..eb5cd54e4f19 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 5b47381758f7..38abb805cb10 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 fd63dcb343ae..560fba15bbad 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 a9c3f316f4c2..f43ce16368cb 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 bc3656f0846f..35b1ecacd505 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 8408c93459a6..f60fe7f8affc 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 1dcfcf7bbb36..e66e3c5a9944 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 3d9b78acf6ed..a8bd2cc34a51 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 0674f118c04b..90bcc04d1212 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 1455669fbc85..ba1987bc1d88 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 f13cb0b03884..45a831daee14 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 aaf51b3d8a68..6cc013071223 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 72ddc8f9b024..1e69b28fa4de 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 9527793b179e..71c9eeafc594 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 1dcb3cfd349d..3b3983e5164e 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 13f69c1b793e..a8c01b3db73c 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 5795cc9b6d92..c28563764a2d 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 718ce5de62f8..9f4ea68f4c64 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 41e84f9e1a84..31bd7af804e0 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 c64ee7604058..c6116aa48bdb 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 e04e2017265f..f21c4cedfb71 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 a57e5413e9aa..c9c4a6c31f49 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 f24b52bb409c..881bccb90062 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 42ad0fece020..94cad918cab8 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 f24b52bb409c..881bccb90062 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 0743fe99056c..4b710853f329 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 d19438aceb16..4aeb9855ff2b 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 15fe8c8370e8..525d4231eb4c 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 ee53b7cfbcec..ee9ae6a47d2f 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 66d33a7bf51a..ff60a322dc1d 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 d5c0231f7652..78e6ed60c176 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 ce74b84aa1e4..8bb9277ba42b 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 eacb7a80cdb8..03fb2238989c 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 62ae06b55152..b95d69c95fc7 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 e7045a72b51b..631a41346282 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 06c7ccb98120..5796603a761a 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 5e880a95c2de..9027ca18fc79 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 6316452511b4..8358dbbfafa5 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 0aabbe5f96ab..d5250a4581db 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 44c8f13acb96..8e0b889f5191 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 7851111910d2..c2f71c38d83e 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 82783b3a172a..a0c5f94a2845 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 c2a96c6a810e..1fb610bad36e 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 259642466187..1f3ea486bd08 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 60afd6d8352f..828d25fbe71b 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 925f73870ea3..54e1f41e9ed8 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 e40d3519788d..b8f1f58b5691 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 c304c14f6073..d680b66b56fa 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 6d7e86f64944..34da30555fb3 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 @@ public class BatterySaverUtils { * - 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 93a8df41c673..cd3d6a84a352 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 @@ public class AppOpItem { 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 @@ public class AppOpItem { 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 1036c9916c8b..d8ca63960b30 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.broadcast.BroadcastDispatcher; 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 @@ import javax.inject.Inject; @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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon DumpManager dumpManager, PermissionFlagsCache cache, AudioManager audioManager, + IndividualSensorPrivacyController sensorPrivacyController, BroadcastDispatcher dispatcher ) { mDispatcher = dispatcher; @@ -129,7 +135,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon 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 c2c67903da86..9be3566e1f63 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.content.Intent; 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 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener 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 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener mBgExecutor = bgExecutor; mImageExporter = exporter; mImageTileSet = new ImageTileSet(); - mLayoutInflater = mContext.getSystemService(LayoutInflater.class); } /** @@ -114,7 +111,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener mEdit.setOnClickListener(this::onClicked); mShare.setOnClickListener(this::onClicked); - mPreview.setImageDrawable(mImageTileSet.getDrawable()); + //mPreview.setImageDrawable(mImageTileSet.getDrawable()); mConnection.start(this::startCapture); } @@ -242,6 +239,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener 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 d4a2b4157338..b20c45780183 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 @@ public class StatusBar extends SystemUI implements DemoMode, && 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 231fe08e6a99..32d15ed41648 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 @@ import java.util.Set; 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 02143a750cae..bc322f7f18fc 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 androidx.test.filters.SmallTest; 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 @@ public class AppOpsControllerTest extends SysuiTestCase { private PermissionFlagsCache mFlagsCache; @Mock private PackageManager mPackageManager; + @Mock + private IndividualSensorPrivacyController mSensorPrivacyController; @Mock(stubOnly = true) private AudioManager mAudioManager; @Mock() @@ -118,12 +124,18 @@ public class AppOpsControllerTest extends SysuiTestCase { 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 @@ public class AppOpsControllerTest extends SysuiTestCase { 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 @@ public class AppOpsControllerTest extends SysuiTestCase { 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 @@ public class AppOpsControllerTest extends SysuiTestCase { 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 1a63dded4298..825392762c8c 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 @@ public class FaceService extends SystemService implements BiometricServiceCallba @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 @@ public class FaceService extends SystemService implements BiometricServiceCallba 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 32428ac13114..cc24b8960e75 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 @@ public interface ServiceProvider { 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 211d79c6a263..d2673d2969c9 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 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { 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 d60bb79de2d7..afc7f6485bc9 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.BiometricFaceConstants; 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 @@ public class FaceEnrollClient extends EnrollClient<ISession> { @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 @@ public class FaceEnrollClient extends EnrollClient<ISession> { 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 @@ public class FaceEnrollClient extends EnrollClient<ISession> { 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 f7feffddb343..e685ee2899af 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 class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { 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 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { 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 9ed8f789aaa2..4142a52c9253 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 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { 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 775d8d417dda..e46661a5e985 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 class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { 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 d9ee9a306f07..13dc0b9be21f 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } 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 54f30a954c33..173adce00cd9 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 @@ final class DisplayPowerState { 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 @@ final class DisplayPowerState { 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 5b3db011b427..5f7d93867331 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 @@ public final class FontManagerService extends IFontManager.Stub { @Override public FontConfig getFontConfig() throws RemoteException { - return getCurrentFontSettings().getSystemFontConfig(); + return getSystemFontConfig(); } /* package */ static class SystemFontException extends AndroidException { @@ -103,7 +103,7 @@ public final class FontManagerService extends IFontManager.Stub { if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) { return null; } - return mService.getCurrentFontSettings().getSerializedSystemFontMap(); + return mService.getCurrentFontMap(); } }); publishBinderService(Context.FONT_SERVICE, mService); @@ -162,7 +162,7 @@ public final class FontManagerService extends IFontManager.Stub { @GuardedBy("FontManagerService.this") @Nullable - private SystemFontSettings mCurrentFontSettings = null; + private SharedMemory mSerializedFontMap = null; private FontManagerService(Context context) { mContext = context; @@ -188,12 +188,12 @@ public final class FontManagerService extends IFontManager.Stub { 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 @@ public final class FontManagerService extends IFontManager.Stub { synchronized (FontManagerService.this) { mUpdatableFontDir.installFontFile(fd, pkcs7Signature); // Create updated font map in the next getSerializedSystemFontMap() call. - mCurrentFontSettings = null; + mSerializedFontMap = null; } } @@ -245,69 +245,44 @@ public final class FontManagerService extends IFontManager.Stub { 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; - - 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; - } - - public @NonNull SharedMemory getSerializedSystemFontMap() { - return mSerializedSystemFontMap; - } - - public @NonNull FontConfig getSystemFontConfig() { - return mSystemFontConfig; + /** + * Returns an active system font configuration. + */ + public @NonNull FontConfig getSystemFontConfig() { + if (mUpdatableFontDir != null) { + return mUpdatableFontDir.getSystemFontConfig(); + } else { + return SystemFonts.getSystemPreinstalledFontConfig(); } + } - public @NonNull Map<String, FontFamily[]> getSystemFallbackMap() { - return mSystemFallbackMap; - } + /** + * 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); - public @NonNull Map<String, Typeface> getSystemTypefaceMap() { - return mSystemTypefaceMap; + return Typeface.serializeFontMap(typefaceMap); + } catch (IOException | ErrnoException e) { + Slog.w(TAG, "Failed to serialize updatable font map. " + + "Retrying with system image fonts.", e); } - 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 fd5c020b1a15..5a01a97dff1a 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.Font; 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 @@ public class FontManagerShellCommand extends ShellCommand { } /* 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 @@ public class FontManagerShellCommand extends ShellCommand { 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 @@ public class FontManagerShellCommand extends ShellCommand { } 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 b5b93d6d8ecd..142f64f0a510 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.ICancellationSignal; 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 @@ public class LocationManagerService extends ILocationManager.Stub { 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 e218dc174ae8..4eaac2e44da8 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.IDataLoaderStatusListener; 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 c27e670c4c99..d2fc5b4c0967 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 @@ public class PackageManagerService extends IPackageManager.Stub } 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 @@ public class PackageManagerService extends IPackageManager.Stub @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 @@ public class PackageManagerService extends IPackageManager.Stub } 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 8c31d88c6f15..aff871118a34 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 @@ public class PermissionManagerService extends IPermissionManager.Stub { // - 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 c073b430c8df..89e7986fc4bc 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } 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 54d05124c114..db4b6d0a3005 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 @@ public final class PowerManagerService extends SystemService 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 @@ public final class PowerManagerService extends SystemService 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 @@ public final class PowerManagerService extends SystemService * * 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 @@ public final class PowerManagerService extends SystemService | 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 @@ public final class PowerManagerService extends SystemService * 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 43f8a3a131d2..57e39b6c6829 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.content.Context.BIND_INCLUDE_CAPABILITIES; 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.CancellationSignal; 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 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol boolean mIsDispatched; private final Object mLock = new Object(); + private final long mRequestStartTimeMillis; RotationRequest( @NonNull RotationResolverInternal.RotationResolverCallbackInternal @@ -125,6 +130,7 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol mPackageName = packageName; mIRotationResolverCallback = new RotationResolverCallback(); mCancellationSignalInternal = cancellationSignal; + mRequestStartTimeMillis = SystemClock.elapsedRealtime(); } @@ -164,7 +170,10 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol } mIsFulfilled = true; mCallbackInternal.onSuccess(rotation); - logStats(rotation); + final long timeToCalculate = + SystemClock.elapsedRealtime() - mRequestStartTimeMillis; + logRotationStats(mProposedRotation, mCurrentRotation, rotation, + timeToCalculate); } } @@ -177,7 +186,10 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol } mIsFulfilled = true; mCallbackInternal.onFailure(error); - logStats(error); + final long timeToCalculate = + SystemClock.elapsedRealtime() - mRequestStartTimeMillis; + logRotationStats(mProposedRotation, mCurrentRotation, RESOLUTION_FAILURE, + timeToCalculate); } } @@ -196,10 +208,6 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol } } - - 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 f0e2d79685b9..8a1c7785fecd 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 @@ package com.android.server.rotationresolver; 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 @@ final class RotationResolverManagerPerUserService extends 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 0377d2310426..4a37e7960912 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 @@ package com.android.server.rotationresolver; 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.rotationresolver.RotationResolverInternal; 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 @@ public class RotationResolverManagerService extends /** 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 @@ public class RotationResolverManagerService extends } else { Slog.w(TAG, "Rotation Resolver service is disabled."); callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED); + logRotationStats(proposedRotation, currentRotation, RESOLUTION_DISABLED); } } } @@ -178,4 +195,36 @@ public class RotationResolverManagerService extends 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 509cbdef41ff..3bb4c74b7dc0 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 class ActivityRecord extends WindowToken implements WindowManagerService.A 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 class ActivityRecord extends WindowToken implements WindowManagerService.A 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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** @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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * @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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // 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 f0db3f9855df..404773d1b257 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.ActivityManagerInternal.ALLOW_NON_FULL; 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 4a90bbcc6623..eee27c72e583 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 @@ public class BarController { 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 2a40500258c9..0aaa1a1752bf 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.SparseBooleanArray; 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp && 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * 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 398049fb97c3..267f67759a24 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 @@ class InsetsStateController { 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 @@ class InsetsStateController { 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 @@ class InsetsStateController { 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 @@ class InsetsStateController { * @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 44ce4de529b0..02a43b74aa33 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 @@ public class Letterbox { 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 @@ public class Letterbox { * @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 @@ public class Letterbox { 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 @@ public class Letterbox { for (LetterboxSurface surface : mSurfaces) { surface.remove(); } + mBehind.remove(); } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ @@ -166,6 +175,9 @@ public class Letterbox { return true; } } + if (mBehind.needsApplySurfaceChanges()) { + return true; + } return false; } @@ -173,6 +185,11 @@ public class Letterbox { 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 ec1588d15320..6a3110f52c91 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_PRIMAR 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 @@ class Task extends WindowContainer<WindowContainer> { 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); - } - - fitWithinBounds(outOverrideBounds, parentBounds, - (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), - (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); + computeFreeformBounds(outOverrideBounds, newParentConfig); + return; + } - // Prevent to overlap caption with stable insets. - final int offsetTop = parentBounds.top - outOverrideBounds.top; - if (offsetTop > 0) { - outOverrideBounds.offset(0, offsetTop); - } + 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); } } - /** - * 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 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); + } + } + + /** + * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation + * change and the requested orientation is different from the parent. + */ + 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 @@ class Task extends WindowContainer<WindowContainer> { 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 @@ class Task extends WindowContainer<WindowContainer> { // 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 @@ class Task extends WindowContainer<WindowContainer> { @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 @@ class Task extends WindowContainer<WindowContainer> { } 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 @@ class Task extends WindowContainer<WindowContainer> { 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 03fca1137e47..dd4ee877c05b 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 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< @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 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } 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 b6fabee33d60..8e6a778c351d 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 @@ public class WindowManagerService extends IWindowManager.Stub // 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * 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 a3a9c1ce9219..badd29aba968 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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 @@ public class WindowManagerShellCommand extends ShellCommand { // 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 @@ public class WindowManagerShellCommand extends ShellCommand { + 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 043844b2e66b..1b81914bbe7c 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 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } // 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); - } - 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 (!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; } - 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()); + } + 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); } - 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 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } 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 093106f123e5..9a7823e35a01 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + /** + * 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** - * @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 6fabc589cf95..dfa6083691a9 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -210,7 +210,17 @@ public: 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 091e688743dd..5453de14a5f1 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.LocalServices; 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 @@ public class PeopleService extends SystemService { 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 752141598c9d..9a9a17112245 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 @@ public class DataManager { 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 63330d518297..161d3163c1cf 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 @@ public final class DataManagerTest { } @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 533dc1708896..1d0b595d8fc1 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 @@ public class PowerManagerServiceTest { } @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 83282a5b8e5a..4bea9a2eea45 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.P; 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.ActivityTaskManager; 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 @@ public class DisplayContentTests extends WindowTestsBase { // 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 @@ public class DisplayContentTests extends WindowTestsBase { // 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 @@ public class DisplayContentTests extends WindowTestsBase { 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 @@ public class DisplayContentTests extends WindowTestsBase { // | | ---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 2f3004bf6832..a045100c4cd8 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 @@ public class LetterboxTest { 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 @@ public class LetterboxTest { 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 @@ public class LetterboxTest { } @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 class LetterboxTest { 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 @@ public class LetterboxTest { 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 @@ public class LetterboxTest { 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 371e6802ced7..942e1c91989c 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.spyOn; 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 @@ public class SizeCompatTests extends WindowTestsBase { 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 b0b8afd6c3a4..df5b48a038f3 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_PORTRAIT; 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 @@ public class WindowContainerTests extends WindowTestsBase { 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 263aa194a108..3231f8b6551a 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 @@ public class WindowStateTests extends WindowTestsBase { 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 39976a5a2af1..b2646f281eb9 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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 @@ public class WmDisplayCutoutTest { @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 b359ebed2683..fadf0e1b84d9 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -554,7 +554,8 @@ public final class PhysicalChannelConfig implements Parcelable { } 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 59e375fa3bd6..f474ec2c389c 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 @@ class CloseImeWindowToHomeTest( 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 24b1854fbf6c..1d479fc14d29 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 @@ public class SingleScanSettings implements Parcelable { private static final String TAG = "SingleScanSettings"; public int scanType; + public boolean enable6GhzRnr; public ArrayList<ChannelSettings> channelSettings; public ArrayList<HiddenNetwork> hiddenNetworks; @@ -50,6 +51,7 @@ public class SingleScanSettings implements Parcelable { return false; } return scanType == settings.scanType + && enable6GhzRnr == settings.enable6GhzRnr && channelSettings.equals(settings.channelSettings) && hiddenNetworks.equals(settings.hiddenNetworks); } @@ -57,7 +59,7 @@ public class SingleScanSettings implements Parcelable { /** override hash code */ @Override public int hashCode() { - return Objects.hash(scanType, channelSettings, hiddenNetworks); + return Objects.hash(scanType, channelSettings, hiddenNetworks, enable6GhzRnr); } @@ -83,6 +85,7 @@ public class SingleScanSettings implements Parcelable { Log.wtf(TAG, "Invalid scan type " + scanType); } out.writeInt(scanType); + out.writeBoolean(enable6GhzRnr); out.writeTypedList(channelSettings); out.writeTypedList(hiddenNetworks); } @@ -100,6 +103,7 @@ public class SingleScanSettings implements Parcelable { 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 db2eb99297c2..ef2653204af5 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.SoftApInfo; 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 class WifiNl80211Manager { */ 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 @@ public class WifiNl80211Manager { } /** + * @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 @@ public class WifiNl80211Manager { * @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 @@ public class WifiNl80211Manager { } 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 905920888012..fd595fa5660c 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 @@ public class SingleScanSettingsTest { 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 9ee0acbfbaa2..4b03a49e40bb 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.SoftApInfo; 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 @@ public class WifiNl80211ManagerTest { 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 @@ public class WifiNl80211ManagerTest { // 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 @@ public class WifiNl80211ManagerTest { 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 @@ public class WifiNl80211ManagerTest { 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 @@ public class WifiNl80211ManagerTest { 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) { |