Merge "Fixed the logic when dynamic privacy is enabled" into sc-dev
diff --git a/Android.bp b/Android.bp
index 381e046..4a22369 100644
--- a/Android.bp
+++ b/Android.bp
@@ -313,6 +313,7 @@
libs: [
"app-compat-annotations",
"ext",
+ "framework-connectivity-annotations",
"framework-updatable-stubs-module_libs_api",
"unsupportedappusage",
],
diff --git a/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java b/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java
new file mode 100644
index 0000000..5d744cd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.text;
+
+import android.graphics.fonts.SystemFonts;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class SystemFontsPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void getAvailableFonts() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ SystemFonts.resetAvailableFonts();
+ System.gc();
+ state.resumeTiming();
+
+ SystemFonts.getAvailableFonts();
+ }
+ }
+}
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 5a2f702..30fb4c6 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -98,13 +98,13 @@
method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
}
- public static final class AppSearchSchema.Int64PropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ public static final class AppSearchSchema.LongPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
}
- public static final class AppSearchSchema.Int64PropertyConfig.Builder {
- ctor public AppSearchSchema.Int64PropertyConfig.Builder(@NonNull String);
- method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig build();
- method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig.Builder setCardinality(int);
+ public static final class AppSearchSchema.LongPropertyConfig.Builder {
+ ctor public AppSearchSchema.LongPropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.LongPropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.LongPropertyConfig.Builder setCardinality(int);
}
public abstract static class AppSearchSchema.PropertyConfig {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index c1fcd6c..3619a56 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -182,7 +182,7 @@
@IntDef(
value = {
DATA_TYPE_STRING,
- DATA_TYPE_INT64,
+ DATA_TYPE_LONG,
DATA_TYPE_DOUBLE,
DATA_TYPE_BOOLEAN,
DATA_TYPE_BYTES,
@@ -195,7 +195,7 @@
public static final int DATA_TYPE_STRING = 1;
/** @hide */
- public static final int DATA_TYPE_INT64 = 2;
+ public static final int DATA_TYPE_LONG = 2;
/** @hide */
public static final int DATA_TYPE_DOUBLE = 3;
@@ -315,8 +315,8 @@
switch (propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)) {
case PropertyConfig.DATA_TYPE_STRING:
return new StringPropertyConfig(propertyBundle);
- case PropertyConfig.DATA_TYPE_INT64:
- return new Int64PropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_LONG:
+ return new LongPropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_DOUBLE:
return new DoublePropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_BOOLEAN:
@@ -485,8 +485,13 @@
}
}
- /** Configuration for a property containing a 64-bit integer. */
- public static final class Int64PropertyConfig extends PropertyConfig {
+ /**
+ * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
+ * @hide
+ */
+ @Deprecated
+ @UnsupportedAppUsage(implicitMember = "")
+ public static class Int64PropertyConfig extends PropertyConfig {
Int64PropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
@@ -497,6 +502,7 @@
private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
/** Creates a new {@link Int64PropertyConfig.Builder}. */
+ @UnsupportedAppUsage
public Builder(@NonNull String propertyName) {
mPropertyName = Objects.requireNonNull(propertyName);
}
@@ -509,6 +515,7 @@
*/
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
+ @UnsupportedAppUsage
public Int64PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
Preconditions.checkArgumentInRange(
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
@@ -518,16 +525,61 @@
/** Constructs a new {@link Int64PropertyConfig} from the contents of this builder. */
@NonNull
+ @UnsupportedAppUsage
public Int64PropertyConfig build() {
Bundle bundle = new Bundle();
bundle.putString(NAME_FIELD, mPropertyName);
- bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_LONG);
bundle.putInt(CARDINALITY_FIELD, mCardinality);
return new Int64PropertyConfig(bundle);
}
}
}
+ /** Configuration for a property containing a 64-bit integer. */
+ // TODO(b/181887768): This should extend directly from PropertyConfig
+ public static final class LongPropertyConfig extends Int64PropertyConfig {
+ LongPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Builder for {@link LongPropertyConfig}. */
+ public static final class Builder {
+ private final String mPropertyName;
+ private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+
+ /** Creates a new {@link LongPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mPropertyName = Objects.requireNonNull(propertyName);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>If this method is not called, the default cardinality is {@link
+ * PropertyConfig#CARDINALITY_OPTIONAL}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public LongPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mCardinality = cardinality;
+ return this;
+ }
+
+ /** Constructs a new {@link LongPropertyConfig} from the contents of this builder. */
+ @NonNull
+ public LongPropertyConfig build() {
+ Bundle bundle = new Bundle();
+ bundle.putString(NAME_FIELD, mPropertyName);
+ bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_LONG);
+ bundle.putInt(CARDINALITY_FIELD, mCardinality);
+ return new LongPropertyConfig(bundle);
+ }
+ }
+ }
+
/** Configuration for a property containing a double-precision decimal number. */
public static final class DoublePropertyConfig extends PropertyConfig {
DoublePropertyConfig(@NonNull Bundle bundle) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index 4a5ecf1..4b92ce6 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -103,8 +103,7 @@
toStatsBuilder
.setNativeLatencyMillis(fromNativeStats.getLatencyMs())
.setTermCount(fromNativeStats.getNumTerms())
- // TODO(b/173532925) query length missing in native
- // .setNativeQueryLength(0)
+ .setQueryLength(fromNativeStats.getQueryLength())
.setFilteredNamespaceCount(fromNativeStats.getNumNamespacesFiltered())
.setFilteredSchemaTypeCount(fromNativeStats.getNumSchemaTypesFiltered())
.setRequestedPageSize(fromNativeStats.getRequestedPageSize())
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index 0cdad37..9ce916f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -199,7 +199,7 @@
case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
documentBuilder.setPropertyString(propertyName, EMPTY_STRING_ARRAY);
break;
- case AppSearchSchema.PropertyConfig.DATA_TYPE_INT64:
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
documentBuilder.setPropertyLong(propertyName, EMPTY_LONG_ARRAY);
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index 80f7007..3e4e7d2 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
@@ -133,7 +133,7 @@
case STRING:
return toStringPropertyConfig(proto);
case INT64:
- return new AppSearchSchema.Int64PropertyConfig.Builder(proto.getPropertyName())
+ return new AppSearchSchema.LongPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.build();
case DOUBLE:
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/RemoveStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/RemoveStats.java
new file mode 100644
index 0000000..b900c49
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/RemoveStats.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.RemoveByDocumentIdRequest;
+import android.app.appsearch.SearchSpec;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class holds detailed stats for {@link
+ * android.app.appsearch.AppSearchSession#remove(RemoveByDocumentIdRequest)} and {@link
+ * android.app.appsearch.AppSearchSession#remove(String, SearchSpec)}
+ *
+ * @hide
+ */
+public final class RemoveStats {
+ @IntDef(
+ value = {
+ // It needs to be sync with DeleteType.Code in
+ // external/icing/proto/icing/proto/logging.proto#DeleteStatsProto
+ UNKNOWN,
+ SINGLE,
+ QUERY,
+ NAMESPACE,
+ SCHEMA_TYPE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeleteType {}
+
+ /** Default. Should never be used. */
+ public static final int UNKNOWN = 0;
+ /** Delete by namespace + id. */
+ public static final int SINGLE = 1;
+ /** Delete by query. */
+ public static final int QUERY = 2;
+ /** Delete by namespace. */
+ public static final int NAMESPACE = 3;
+ /** Delete by schema type. */
+ public static final int SCHEMA_TYPE = 4;
+
+ @NonNull private final String mPackageName;
+ @NonNull private final String mDatabase;
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal
+ * state.
+ */
+ @AppSearchResult.ResultCode private final int mStatusCode;
+
+ private final int mTotalLatencyMillis;
+ private final int mNativeLatencyMillis;
+ @DeleteType private final int mNativeDeleteType;
+ private final int mNativeNumDocumentsDeleted;
+
+ RemoveStats(@NonNull Builder builder) {
+ Objects.requireNonNull(builder);
+ mPackageName = builder.mPackageName;
+ mDatabase = builder.mDatabase;
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDeleteType = builder.mNativeDeleteType;
+ mNativeNumDocumentsDeleted = builder.mNativeNumDocumentsDeleted;
+ }
+
+ /** Returns calling package name. */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns calling database name. */
+ @NonNull
+ public String getDatabase() {
+ return mDatabase;
+ }
+
+ /** Returns status code for this remove. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this remove in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time in millis spent in the native code. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns what type of delete for this remove call. */
+ @DeleteType
+ public int getDeleteType() {
+ return mNativeDeleteType;
+ }
+
+ /** Returns how many documents get deleted in this call. */
+ public int getDeletedDocumentCount() {
+ return mNativeNumDocumentsDeleted;
+ }
+
+ /** Builder for {@link RemoveStats}. */
+ public static class Builder {
+ @NonNull final String mPackageName;
+ @NonNull final String mDatabase;
+ @AppSearchResult.ResultCode int mStatusCode;
+ int mTotalLatencyMillis;
+ int mNativeLatencyMillis;
+ @DeleteType int mNativeDeleteType;
+ int mNativeNumDocumentsDeleted;
+
+ /** Constructor for the {@link Builder}. */
+ public Builder(@NonNull String packageName, @NonNull String database) {
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
+ }
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets native latency in millis. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets delete type for this call. */
+ @NonNull
+ public Builder setDeleteType(@DeleteType int nativeDeleteType) {
+ mNativeDeleteType = nativeDeleteType;
+ return this;
+ }
+
+ /** Sets how many documents get deleted for this call. */
+ @NonNull
+ public Builder setDeletedDocumentCount(int nativeNumDocumentsDeleted) {
+ mNativeNumDocumentsDeleted = nativeNumDocumentsDeleted;
+ return this;
+ }
+
+ /** Creates a {@link RemoveStats}. */
+ @NonNull
+ public RemoveStats build() {
+ return new RemoveStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 9723de6..9bfe071 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-a83c33a5a394141fea1d065ce0fab513a62d4bcf
+c6630eba424d98dd54ece674e769d9b0b883e410
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index 22ee501..38500af 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -258,8 +258,7 @@
public @NonNull ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle)
throws IOException {
try {
- return mService.openBlob(blobHandle, mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ return mService.openBlob(blobHandle, mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -316,7 +315,7 @@
@CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
try {
mService.acquireLease(blobHandle, descriptionResId, null, leaseExpiryTimeMillis,
- mContext.getOpPackageName(), mContext.getAttributionTag());
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
e.maybeRethrow(LimitExceededException.class);
@@ -379,7 +378,7 @@
@CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
try {
mService.acquireLease(blobHandle, INVALID_RES_ID, description, leaseExpiryTimeMillis,
- mContext.getOpPackageName(), mContext.getAttributionTag());
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
e.maybeRethrow(LimitExceededException.class);
@@ -498,8 +497,7 @@
*/
public void releaseLease(@NonNull BlobHandle blobHandle) throws IOException {
try {
- mService.releaseLease(blobHandle, mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ mService.releaseLease(blobHandle, mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -604,8 +602,7 @@
@Nullable
public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle) throws IOException {
try {
- return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -900,64 +897,6 @@
}
/**
- * Allow apps with location permission to access this blob data once it is committed using
- * a {@link BlobHandle} representing the blob.
- *
- * <p> This needs to be called before committing the blob using
- * {@link #commit(Executor, Consumer)}.
- *
- * Note that if a caller allows access to the blob using this API in addition to other APIs
- * like {@link #allowPackageAccess(String, byte[])}, then apps satisfying any one of these
- * access conditions will be allowed to access the blob.
- *
- * @param permissionName the name of the location permission that needs to be granted
- * for the app. This can be either one of
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
- *
- * @throws IOException when there is an I/O error while changing the access.
- * @throws SecurityException when the caller is not the owner of the session.
- * @throws IllegalStateException when the caller tries to change access for a blob which is
- * already committed.
- */
- public void allowPackagesWithLocationPermission(@NonNull String permissionName)
- throws IOException {
- try {
- mSession.allowPackagesWithLocationPermission(permissionName);
- } catch (ParcelableException e) {
- e.maybeRethrow(IOException.class);
- throw new RuntimeException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns {@code true} if access has been allowed for apps with location permission by
- * using {@link #allowPackagesWithLocationPermission(String)}.
- *
- * @param permissionName the name of the location permission that needs to be granted
- * for the app. This can be either one of
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
- *
- * @throws IOException when there is an I/O error while getting the access type.
- * @throws IllegalStateException when the caller tries to get access type from a session
- * which is closed or abandoned.
- */
- public boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName)
- throws IOException {
- try {
- return mSession.arePackagesWithLocationPermissionAllowed(permissionName);
- } catch (ParcelableException e) {
- e.maybeRethrow(IOException.class);
- throw new RuntimeException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Commit the file that was written so far to this session to the blob store maintained by
* the system.
*
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
index db6cb5c9..39a9fb4 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
@@ -25,13 +25,12 @@
interface IBlobStoreManager {
long createSession(in BlobHandle handle, in String packageName);
IBlobStoreSession openSession(long sessionId, in String packageName);
- ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName,
- in String attributionTag);
+ ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
void abandonSession(long sessionId, in String packageName);
void acquireLease(in BlobHandle handle, int descriptionResId, in CharSequence description,
- long leaseTimeoutMillis, in String packageName, in String attributionTag);
- void releaseLease(in BlobHandle handle, in String packageName, in String attributionTag);
+ long leaseTimeoutMillis, in String packageName);
+ void releaseLease(in BlobHandle handle, in String packageName);
long getRemainingLeaseQuotaBytes(String packageName);
void waitForIdle(in RemoteCallback callback);
@@ -40,6 +39,5 @@
void deleteBlob(long blobId);
List<BlobHandle> getLeasedBlobs(in String packageName);
- LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName,
- in String attributionTag);
+ LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName);
}
\ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
index e3ccfb8..4035b96 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
@@ -26,12 +26,10 @@
void allowPackageAccess(in String packageName, in byte[] certificate);
void allowSameSignatureAccess();
void allowPublicAccess();
- void allowPackagesWithLocationPermission(in String permissionName);
boolean isPackageAccessAllowed(in String packageName, in byte[] certificate);
boolean isSameSignatureAccessAllowed();
boolean isPublicAccessAllowed();
- boolean arePackagesWithLocationPermissionAllowed(in String permissionName);
long getSize();
void close();
diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java
index 6e4b2f7..bfc5826 100644
--- a/apex/blobstore/framework/java/android/app/blob/XmlTags.java
+++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java
@@ -38,7 +38,6 @@
public static final String ATTR_TYPE = "t";
public static final String TAG_ALLOWED_PACKAGE = "wl";
public static final String ATTR_CERTIFICATE = "ct";
- public static final String TAG_ALLOWED_PERMISSION = "ap";
// For BlobHandle
public static final String TAG_BLOB_HANDLE = "bh";
@@ -56,7 +55,4 @@
public static final String TAG_LEASEE = "l";
public static final String ATTR_DESCRIPTION_RES_NAME = "rn";
public static final String ATTR_DESCRIPTION = "d";
-
- // Generic
- public static final String ATTR_VALUE = "val";
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index 09260b7..0d17bbc 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -15,30 +15,19 @@
*/
package com.android.server.blob;
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
-import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.blob.XmlTags.ATTR_CERTIFICATE;
import static android.app.blob.XmlTags.ATTR_PACKAGE;
import static android.app.blob.XmlTags.ATTR_TYPE;
-import static android.app.blob.XmlTags.ATTR_VALUE;
import static android.app.blob.XmlTags.TAG_ALLOWED_PACKAGE;
-import static android.app.blob.XmlTags.TAG_ALLOWED_PERMISSION;
-
-import static com.android.server.blob.BlobStoreConfig.TAG;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.permission.PermissionManager;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
-import android.util.Slog;
import com.android.internal.util.XmlUtils;
@@ -64,27 +53,21 @@
ACCESS_TYPE_PUBLIC,
ACCESS_TYPE_SAME_SIGNATURE,
ACCESS_TYPE_ALLOWLIST,
- ACCESS_TYPE_LOCATION_PERMISSION,
})
@interface AccessType {}
public static final int ACCESS_TYPE_PRIVATE = 1 << 0;
public static final int ACCESS_TYPE_PUBLIC = 1 << 1;
public static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2;
public static final int ACCESS_TYPE_ALLOWLIST = 1 << 3;
- public static final int ACCESS_TYPE_LOCATION_PERMISSION = 1 << 4;
private int mAccessType = ACCESS_TYPE_PRIVATE;
private final ArraySet<PackageIdentifier> mAllowedPackages = new ArraySet<>();
- private final ArraySet<String> mAllowedPermissions = new ArraySet<>();
void allow(BlobAccessMode other) {
if ((other.mAccessType & ACCESS_TYPE_ALLOWLIST) != 0) {
mAllowedPackages.addAll(other.mAllowedPackages);
}
- if ((other.mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) {
- mAllowedPermissions.addAll(other.mAllowedPermissions);
- }
mAccessType |= other.mAccessType;
}
@@ -101,11 +84,6 @@
mAllowedPackages.add(PackageIdentifier.create(packageName, certificate));
}
- void allowPackagesWithLocationPermission(@NonNull String permissionName) {
- mAccessType |= ACCESS_TYPE_LOCATION_PERMISSION;
- mAllowedPermissions.add(permissionName);
- }
-
boolean isPublicAccessAllowed() {
return (mAccessType & ACCESS_TYPE_PUBLIC) != 0;
}
@@ -121,15 +99,8 @@
return mAllowedPackages.contains(PackageIdentifier.create(packageName, certificate));
}
- boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName) {
- if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) == 0) {
- return false;
- }
- return mAllowedPermissions.contains(permissionName);
- }
-
- boolean isAccessAllowedForCaller(Context context, @NonNull String callingPackage,
- @NonNull String committerPackage, int callingUid, @Nullable String attributionTag) {
+ boolean isAccessAllowedForCaller(Context context,
+ @NonNull String callingPackage, @NonNull String committerPackage) {
if ((mAccessType & ACCESS_TYPE_PUBLIC) != 0) {
return true;
}
@@ -153,37 +124,9 @@
}
}
- if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) {
- final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
- for (int i = 0; i < mAllowedPermissions.size(); ++i) {
- final String permission = mAllowedPermissions.valueAt(i);
- if (PermissionManager.checkPackageNamePermission(permission, callingPackage,
- UserHandle.getUserId(callingUid)) != PackageManager.PERMISSION_GRANTED) {
- continue;
- }
- // TODO: Add appropriate message
- if (appOpsManager.noteOpNoThrow(getAppOp(permission), callingUid, callingPackage,
- attributionTag, null /* message */) == AppOpsManager.MODE_ALLOWED) {
- return true;
- }
- }
- }
-
return false;
}
- private static String getAppOp(String permission) {
- switch (permission) {
- case ACCESS_FINE_LOCATION:
- return AppOpsManager.OPSTR_FINE_LOCATION;
- case ACCESS_COARSE_LOCATION:
- return AppOpsManager.OPSTR_COARSE_LOCATION;
- default:
- Slog.w(TAG, "Unknown permission found: " + permission);
- return null;
- }
- }
-
int getAccessType() {
return mAccessType;
}
@@ -205,16 +148,6 @@
}
fout.decreaseIndent();
}
- fout.print("Allowed permissions:");
- if (mAllowedPermissions.isEmpty()) {
- fout.println(" (Empty)");
- } else {
- fout.increaseIndent();
- for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) {
- fout.println(mAllowedPermissions.valueAt(i).toString());
- }
- fout.decreaseIndent();
- }
}
void writeToXml(@NonNull XmlSerializer out) throws IOException {
@@ -226,12 +159,6 @@
XmlUtils.writeByteArrayAttribute(out, ATTR_CERTIFICATE, packageIdentifier.certificate);
out.endTag(null, TAG_ALLOWED_PACKAGE);
}
- for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) {
- out.startTag(null, TAG_ALLOWED_PERMISSION);
- final String permission = mAllowedPermissions.valueAt(i);
- XmlUtils.writeStringAttribute(out, ATTR_VALUE, permission);
- out.endTag(null, TAG_ALLOWED_PERMISSION);
- }
}
@NonNull
@@ -249,10 +176,6 @@
final byte[] certificate = XmlUtils.readByteArrayAttribute(in, ATTR_CERTIFICATE);
blobAccessMode.allowPackageAccess(packageName, certificate);
}
- if (TAG_ALLOWED_PERMISSION.equals(in.getName())) {
- final String permission = XmlUtils.readStringAttribute(in, ATTR_VALUE);
- blobAccessMode.allowPackagesWithLocationPermission(permission);
- }
}
return blobAccessMode;
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index e477156..e116c81 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -263,8 +263,7 @@
return getBlobFile().length();
}
- boolean isAccessAllowedForCaller(@NonNull String callingPackage, int callingUid,
- @Nullable String attributionTag) {
+ boolean isAccessAllowedForCaller(@NonNull String callingPackage, int callingUid) {
// Don't allow the blob to be accessed after it's expiry time has passed.
if (getBlobHandle().isExpired()) {
return false;
@@ -293,7 +292,7 @@
// Check if the caller is allowed access as per the access mode specified
// by the committer.
if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
- callingPackage, committer.packageName, callingUid, attributionTag)) {
+ callingPackage, committer.packageName)) {
return true;
}
}
@@ -316,7 +315,7 @@
// Check if the caller is allowed access as per the access mode specified
// by the committer.
if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
- callingPackage, committer.packageName, callingUid, attributionTag)) {
+ callingPackage, committer.packageName)) {
return true;
}
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 731ba92..beeffd6 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -397,11 +397,11 @@
}
private ParcelFileDescriptor openBlobInternal(BlobHandle blobHandle, int callingUid,
- String callingPackage, String attributionTag) throws IOException {
+ String callingPackage) throws IOException {
synchronized (mBlobsLock) {
final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
- callingPackage, callingUid, attributionTag)) {
+ callingPackage, callingUid)) {
if (blobMetadata == null) {
FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
INVALID_BLOB_ID, INVALID_BLOB_SIZE,
@@ -449,7 +449,7 @@
private void acquireLeaseInternal(BlobHandle blobHandle, int descriptionResId,
CharSequence description, long leaseExpiryTimeMillis,
- int callingUid, String callingPackage, String attributionTag) {
+ int callingUid, String callingPackage) {
synchronized (mBlobsLock) {
final int leasesCount = getLeasedBlobsCountLocked(callingUid, callingPackage);
if (leasesCount >= getMaxLeasedBlobs()) {
@@ -470,7 +470,7 @@
final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
- callingPackage, callingUid, attributionTag)) {
+ callingPackage, callingUid)) {
if (blobMetadata == null) {
FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
INVALID_BLOB_ID, INVALID_BLOB_SIZE,
@@ -521,11 +521,11 @@
}
private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
- String callingPackage, String attributionTag) {
+ String callingPackage) {
synchronized (mBlobsLock) {
final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
- callingPackage, callingUid, attributionTag)) {
+ callingPackage, callingUid)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
@@ -632,11 +632,11 @@
}
private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle,
- int callingUid, @NonNull String callingPackage, String attributionTag) {
+ int callingUid, @NonNull String callingPackage) {
synchronized (mBlobsLock) {
final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
- callingPackage, callingUid, attributionTag)) {
+ callingPackage, callingUid)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
@@ -1478,7 +1478,7 @@
@Override
public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle,
- @NonNull String packageName, @Nullable String attributionTag) {
+ @NonNull String packageName) {
Objects.requireNonNull(blobHandle, "blobHandle must not be null");
blobHandle.assertIsValid();
Objects.requireNonNull(packageName, "packageName must not be null");
@@ -1493,7 +1493,7 @@
}
try {
- return openBlobInternal(blobHandle, callingUid, packageName, attributionTag);
+ return openBlobInternal(blobHandle, callingUid, packageName);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
@@ -1502,8 +1502,7 @@
@Override
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
@Nullable CharSequence description,
- @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName,
- @Nullable String attributionTag) {
+ @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName) {
Objects.requireNonNull(blobHandle, "blobHandle must not be null");
blobHandle.assertIsValid();
Preconditions.checkArgument(
@@ -1527,7 +1526,7 @@
try {
acquireLeaseInternal(blobHandle, descriptionResId, description,
- leaseExpiryTimeMillis, callingUid, packageName, attributionTag);
+ leaseExpiryTimeMillis, callingUid, packageName);
} catch (Resources.NotFoundException e) {
throw new IllegalArgumentException(e);
} catch (LimitExceededException e) {
@@ -1536,8 +1535,7 @@
}
@Override
- public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName,
- @Nullable String attributionTag) {
+ public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
Objects.requireNonNull(blobHandle, "blobHandle must not be null");
blobHandle.assertIsValid();
Objects.requireNonNull(packageName, "packageName must not be null");
@@ -1551,7 +1549,7 @@
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
- releaseLeaseInternal(blobHandle, callingUid, packageName, attributionTag);
+ releaseLeaseInternal(blobHandle, callingUid, packageName);
}
@Override
@@ -1621,8 +1619,7 @@
@Override
@Nullable
- public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName,
- @Nullable String attributionTag) {
+ public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
Objects.requireNonNull(blobHandle, "blobHandle must not be null");
blobHandle.assertIsValid();
Objects.requireNonNull(packageName, "packageName must not be null");
@@ -1636,7 +1633,7 @@
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
- return getLeaseInfoInternal(blobHandle, callingUid, packageName, attributionTag);
+ return getLeaseInfoInternal(blobHandle, callingUid, packageName);
}
@Override
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 3f0032f..8eef8ce 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -15,8 +15,6 @@
*/
package com.android.server.blob;
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
-import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR;
import static android.app.blob.XmlTags.ATTR_CREATION_TIME_MS;
import static android.app.blob.XmlTags.ATTR_ID;
@@ -368,21 +366,6 @@
}
@Override
- public void allowPackagesWithLocationPermission(@NonNull String permissionName) {
- assertCallerIsOwner();
- Preconditions.checkArgument(ACCESS_FINE_LOCATION.equals(permissionName)
- || ACCESS_COARSE_LOCATION.equals(permissionName),
- "permissionName is unknown: " + permissionName);
- synchronized (mSessionLock) {
- if (mState != STATE_OPENED) {
- throw new IllegalStateException("Not allowed to change access type in state: "
- + stateToString(mState));
- }
- mBlobAccessMode.allowPackagesWithLocationPermission(permissionName);
- }
- }
-
- @Override
public boolean isPackageAccessAllowed(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
@@ -423,21 +406,6 @@
}
@Override
- public boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName) {
- assertCallerIsOwner();
- Preconditions.checkArgument(ACCESS_FINE_LOCATION.equals(permissionName)
- || ACCESS_COARSE_LOCATION.equals(permissionName),
- "permissionName is unknown: " + permissionName);
- synchronized (mSessionLock) {
- if (mState != STATE_OPENED) {
- throw new IllegalStateException("Not allowed to change access type in state: "
- + stateToString(mState));
- }
- return mBlobAccessMode.arePackagesWithLocationPermissionAllowed(permissionName);
- }
- }
-
- @Override
public void close() {
closeSession(STATE_CLOSED, false /* sendCallback */);
}
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 8b824e8..9fa7810 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -532,9 +532,10 @@
* modest timeliness requirements for its alarms.
*
* <p>
- * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
- * specified is at least a few minutes, as smaller windows are considered practically exact
- * and should use the other APIs provided for exact alarms.
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, apps should not pass in a window of
+ * less than 10 minutes. The system will try its best to accommodate smaller windows if the
+ * alarm is supposed to fire in the near future, but there are no guarantees and the app should
+ * expect any window smaller than 10 minutes to get elongated to 10 minutes.
*
* <p>
* This method can also be used to achieve strict ordering guarantees among
@@ -588,9 +589,10 @@
* if {@code null} is passed as the {@code targetHandler} parameter.
*
* <p>
- * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
- * specified is at least a few minutes, as smaller windows are considered practically exact
- * and should use the other APIs provided for exact alarms.
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, apps should not pass in a window of
+ * less than 10 minutes. The system will try its best to accommodate smaller windows if the
+ * alarm is supposed to fire in the near future, but there are no guarantees and the app should
+ * expect any window smaller than 10 minutes to get elongated to 10 minutes.
*
* @see #setWindow(int, long, long, PendingIntent)
*/
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 0eb2609..5365218 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -530,8 +530,7 @@
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * INTERVAL_DAY;
- // TODO (b/185199076): Tune based on breakage reports.
- private static final long DEFAULT_MIN_WINDOW = 30 * 60 * 1000;
+ private static final long DEFAULT_MIN_WINDOW = 10 * 60 * 1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 * 1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
@@ -1147,6 +1146,18 @@
return when;
}
+ /**
+ * This is the minimum window that can be requested for the given alarm. Windows smaller than
+ * this value will be elongated to match it.
+ * Current heuristic is similar to {@link #maxTriggerTime(long, long, long)}, the minimum
+ * allowed window is either {@link Constants#MIN_WINDOW} or 75% of the alarm's futurity,
+ * whichever is smaller.
+ */
+ long getMinimumAllowedWindow(long nowElapsed, long triggerElapsed) {
+ final long futurity = triggerElapsed - nowElapsed;
+ return Math.min((long) (futurity * 0.75), mConstants.MIN_WINDOW);
+ }
+
// Apply a heuristic to { recurrence interval, futurity of the trigger time } to
// calculate the end of our nominal delivery window for the alarm.
static long maxTriggerTime(long now, long triggerAtTime, long interval) {
@@ -1833,25 +1844,6 @@
}
}
- // Snap the window to reasonable limits.
- if (windowLength > INTERVAL_DAY) {
- Slog.w(TAG, "Window length " + windowLength
- + "ms suspiciously long; limiting to 1 day");
- windowLength = INTERVAL_DAY;
- } else if (windowLength > 0 && windowLength < mConstants.MIN_WINDOW
- && (flags & FLAG_PRIORITIZE) == 0) {
- if (CompatChanges.isChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS,
- callingPackage, UserHandle.getUserHandleForUid(callingUid))) {
- Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to "
- + mConstants.MIN_WINDOW + "ms.");
- windowLength = mConstants.MIN_WINDOW;
- } else {
- // TODO (b/185199076): Remove log once we have some data about what apps will break
- Slog.wtf(TAG, "Short window " + windowLength + "ms specified by "
- + callingPackage);
- }
- }
-
// Sanity check the recurrence interval. This will catch people who supply
// seconds when the API expects milliseconds, or apps trying shenanigans
// around intentional period overflow, etc.
@@ -1883,7 +1875,7 @@
// Try to prevent spamming by making sure apps aren't firing alarms in the immediate future
final long minTrigger = nowElapsed
+ (UserHandle.isCore(callingUid) ? 0L : mConstants.MIN_FUTURITY);
- final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
+ final long triggerElapsed = Math.max(minTrigger, nominalTrigger);
final long maxElapsed;
if (windowLength == 0) {
@@ -1893,6 +1885,25 @@
// Fix this window in place, so that as time approaches we don't collapse it.
windowLength = maxElapsed - triggerElapsed;
} else {
+ // The window was explicitly requested. Snap it to allowable limits.
+ final long minAllowedWindow = getMinimumAllowedWindow(nowElapsed, triggerElapsed);
+ if (windowLength > INTERVAL_DAY) {
+ Slog.w(TAG, "Window length " + windowLength + "ms too long; limiting to 1 day");
+ windowLength = INTERVAL_DAY;
+ } else if ((flags & FLAG_PRIORITIZE) == 0 && windowLength < minAllowedWindow) {
+ // Prioritized alarms are exempt from minimum window limits.
+ if (CompatChanges.isChangeEnabled(
+ AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, callingPackage,
+ UserHandle.getUserHandleForUid(callingUid))) {
+ Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to "
+ + minAllowedWindow + "ms.");
+ windowLength = minAllowedWindow;
+ } else {
+ // TODO (b/185199076): Remove temporary log to catch breaking apps.
+ Slog.wtf(TAG, "Short window " + windowLength + "ms specified by "
+ + callingPackage);
+ }
+ }
maxElapsed = triggerElapsed + windowLength;
}
synchronized (mLock) {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index f5bee6c..260c8a4 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -258,7 +258,7 @@
public void runDisableAppDataIsolation() throws RemoteException {
if (!SystemProperties.getBoolean(
- ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
throw new IllegalStateException("Storage app data isolation is not enabled.");
}
final String pkgName = nextArg();
diff --git a/core/api/current.txt b/core/api/current.txt
index 6fd1715..37dd6b8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -141,7 +141,6 @@
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
- field public static final String REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
@@ -7906,10 +7905,8 @@
public static class BlobStoreManager.Session implements java.io.Closeable {
method public void abandon() throws java.io.IOException;
method public void allowPackageAccess(@NonNull String, @NonNull byte[]) throws java.io.IOException;
- method public void allowPackagesWithLocationPermission(@NonNull String) throws java.io.IOException;
method public void allowPublicAccess() throws java.io.IOException;
method public void allowSameSignatureAccess() throws java.io.IOException;
- method public boolean arePackagesWithLocationPermissionAllowed(@NonNull String) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public void commit(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws java.io.IOException;
method public long getSize() throws java.io.IOException;
@@ -11883,7 +11880,6 @@
field public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11; // 0xb
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
- field public String[] attributionTags;
field public int colorMode;
field public int configChanges;
field public int documentLaunchMode;
@@ -12075,6 +12071,7 @@
method public final int getLogoResource();
method public boolean isEnabled();
field public android.content.pm.ApplicationInfo applicationInfo;
+ field public String[] attributionTags;
field public int descriptionRes;
field public boolean directBootAware;
field public boolean enabled;
@@ -51985,6 +51982,7 @@
method public int getSubtypeCount();
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public CharSequence loadLabel(android.content.pm.PackageManager);
+ method public boolean shouldShowInInputMethodPicker();
method public boolean suppressesSpellChecker();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1a77355..8e13c33 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -211,6 +211,7 @@
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
+ field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA";
field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
@@ -4996,11 +4997,15 @@
public final class SatellitePvt implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public android.location.SatellitePvt.ClockInfo getClockInfo();
+ method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
+ method public int getFlags();
method @FloatRange public double getIonoDelayMeters();
- method @NonNull public android.location.SatellitePvt.PositionEcef getPositionEcef();
+ method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
method @FloatRange public double getTropoDelayMeters();
- method @NonNull public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
+ method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
+ method public boolean hasIono();
+ method public boolean hasPositionVelocityClockInfo();
+ method public boolean hasTropo();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR;
}
@@ -5009,6 +5014,7 @@
ctor public SatellitePvt.Builder();
method @NonNull public android.location.SatellitePvt build();
method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
+ method @NonNull public android.location.SatellitePvt.Builder setFlags(int);
method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange double);
method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange double);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c8e365e..12d9bee 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2103,6 +2103,7 @@
public final class DeviceConfig {
field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
field public static final String NAMESPACE_ANDROID = "android";
+ field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 295943d..854c9f2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -970,8 +970,7 @@
private UiTranslationController mUiTranslationController;
private SplashScreen mSplashScreen;
- /** @hide */
- SplashScreenView mSplashScreenView;
+ private SplashScreenView mSplashScreenView;
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
@@ -1631,16 +1630,14 @@
}
}
- /**
- * Clear the splash screen view if exist.
- * @hide
- */
- public void detachSplashScreenView() {
- synchronized (this) {
- if (mSplashScreenView != null) {
- mSplashScreenView = null;
- }
- }
+ /** @hide */
+ public void setSplashScreenView(SplashScreenView v) {
+ mSplashScreenView = v;
+ }
+
+ /** @hide */
+ SplashScreenView getSplashScreenView() {
+ return mSplashScreenView;
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3ebf545..f626d4b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3509,7 +3509,8 @@
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
- r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
+ r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
+ appContext.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
@@ -3801,7 +3802,8 @@
for (int i=0; i<N; i++) {
ReferrerIntent intent = intents.get(i);
intent.setExtrasClassLoader(r.activity.getClassLoader());
- intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
+ intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
+ r.activity.getAttributionSource());
r.activity.mFragments.noteStateNotSaved();
mInstrumentation.callActivityOnNewIntent(r.activity, intent);
}
@@ -4049,10 +4051,7 @@
final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity);
final SplashScreenView view = builder.createFromParcel(parcelable).build();
decorView.addView(view);
- view.cacheRootWindow(r.window);
- view.makeSystemUIColorsTransparent();
- r.activity.mSplashScreenView = view;
- view.attachHostActivity(r.activity);
+ view.attachHostActivityAndSetSystemUIColors(r.activity, r.window);
view.requestLayout();
// Ensure splash screen view is shown before remove the splash screen window.
final ViewRootImpl impl = decorView.getViewRootImpl();
@@ -4094,12 +4093,13 @@
@Override
public void handOverSplashScreenView(@NonNull ActivityClientRecord r) {
- if (r.activity.mSplashScreenView != null) {
- synchronized (this) {
- if (mSplashScreenGlobal != null) {
- mSplashScreenGlobal.dispatchOnExitAnimation(r.token,
- r.activity.mSplashScreenView);
- }
+ final SplashScreenView v = r.activity.getSplashScreenView();
+ if (v == null) {
+ return;
+ }
+ synchronized (this) {
+ if (mSplashScreenGlobal != null) {
+ mSplashScreenGlobal.dispatchOnExitAnimation(r.token, v);
}
}
}
@@ -4241,10 +4241,15 @@
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
+ if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
+ final String attributionTag = data.info.attributionTags[0];
+ context = (ContextImpl) context.createAttributionContext(attributionTag);
+ }
java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess(
- isProtectedComponent(data.info) || isProtectedBroadcast(data.intent));
+ isProtectedComponent(data.info) || isProtectedBroadcast(data.intent),
+ context.getAttributionSource());
data.setExtrasClassLoader(cl);
receiver = packageInfo.getAppFactory()
.instantiateReceiver(cl, data.info.name, data.intent);
@@ -4435,6 +4440,10 @@
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
+ if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
+ final String attributionTag = data.info.attributionTags[0];
+ context = (ContextImpl) context.createAttributionContext(attributionTag);
+ }
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
@@ -4469,7 +4478,8 @@
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
- data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
+ data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),
+ s.getAttributionSource());
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
@@ -4499,7 +4509,8 @@
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
- data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
+ data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),
+ s.getAttributionSource());
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
@@ -4588,7 +4599,8 @@
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
- data.args.prepareToEnterProcess(isProtectedComponent(createData.info));
+ data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
+ s.getAttributionSource());
}
int res;
if (!data.taskRemoved) {
@@ -5241,7 +5253,8 @@
try {
if (ri.mData != null) {
ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
- ri.mData.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
+ ri.mData.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
+ r.activity.getAttributionSource());
}
if (DEBUG_RESULTS) Slog.v(TAG,
"Delivering result to activity " + r + " : " + ri);
@@ -7342,6 +7355,10 @@
throw new RuntimeException(e);
}
}
+ if (info.attributionTags != null && info.attributionTags.length > 0) {
+ final String attributionTag = info.attributionTags[0];
+ c = c.createAttributionContext(attributionTag);
+ }
try {
final java.lang.ClassLoader cl = c.getClassLoader();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 010f4e4..ed00436 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7394,20 +7394,27 @@
/** @hide */
public void setUserRestriction(int code, boolean restricted, IBinder token) {
- setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
+ setUserRestriction(code, restricted, token, (Map<String, String[]>) null);
}
- /** @hide */
+ /**
+ * An empty array of attribution tags means exclude all tags under that package.
+ * @hide
+ */
public void setUserRestriction(int code, boolean restricted, IBinder token,
- String[] exceptionPackages) {
- setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId());
+ @Nullable Map<String, String[]> excludedPackageTags) {
+ setUserRestrictionForUser(code, restricted, token, excludedPackageTags,
+ mContext.getUserId());
}
- /** @hide */
+ /**
+ * An empty array of attribution tags means exclude all tags under that package.
+ * @hide
+ */
public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
- String[] exceptionPackages, int userId) {
+ @Nullable Map<String, String[]> excludedPackageTags, int userId) {
try {
- mService.setUserRestriction(code, restricted, token, userId, exceptionPackages);
+ mService.setUserRestriction(code, restricted, token, userId, excludedPackageTags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -7949,7 +7956,7 @@
*/
public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
try {
- return mService.checkOperationRaw(op, uid, packageName);
+ return mService.checkOperationRaw(op, uid, packageName, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 341b9c5..2de0ddb 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -29,6 +29,7 @@
import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
import com.android.internal.util.function.TriFunction;
/**
@@ -45,12 +46,14 @@
* @param code The op code to check.
* @param uid The UID for which to check.
* @param packageName The package for which to check.
- * @param superImpl The super implementation.
+ * @param attributionTag The attribution tag for which to check.
* @param raw Whether to check the raw op i.e. not interpret the mode based on UID state.
+ * @param superImpl The super implementation.
* @return The app op check result.
*/
- int checkOperation(int code, int uid, String packageName, boolean raw,
- QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl);
+ int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag,
+ boolean raw,
+ QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl);
/**
* Allows overriding check audio operation behavior.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9ce37e4..73c17b9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1774,7 +1774,8 @@
intent.setExtrasClassLoader(getClassLoader());
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
- intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
+ intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
+ getAttributionSource());
}
return intent;
} catch (RemoteException e) {
@@ -3035,8 +3036,16 @@
}
}
+ final String attributionTag;
+ if (activityInfo.attributionTags != null && activityInfo.attributionTags.length > 0) {
+ attributionTag = activityInfo.attributionTags[0];
+ } else {
+ attributionTag = null;
+ }
+
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
- null, null, activityInfo.splitName, activityToken, null, 0, classLoader, null);
+ attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
+ null);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
context.mIsConfigurationBasedContext = true;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ea6c874..4446fb7 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1651,7 +1651,8 @@
intent.setExtrasClassLoader(cl);
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
- intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
+ intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
+ mContext.getAttributionSource());
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index b216e91..a71cffe 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -48,6 +48,13 @@
String SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED = "set_auto_detection_enabled";
/**
+ * A shell command that prints whether the telephony-based time zone detection feature is
+ * supported on the device.
+ * @hide
+ */
+ String SHELL_COMMAND_IS_TELEPHONY_DETECTION_SUPPORTED = "is_telephony_detection_supported";
+
+ /**
* A shell command that prints whether the geolocation-based time zone detection feature is
* supported on the device.
* @hide
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 4032663..52d4c71 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1190,6 +1190,11 @@
return devices;
}
+ /** {@hide} */
+ public void prepareToEnterProcess(AttributionSource attributionSource) {
+ setAttributionSource(attributionSource);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof BluetoothDevice) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6ab1975..54b39bd 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -1034,14 +1034,14 @@
}
/** {@hide} */
- public void prepareToEnterProcess() {
+ public void prepareToEnterProcess(AttributionSource source) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
// We can't recursively claim that this data is from a protected
// component, since it may have been filled in by a malicious app
- item.mIntent.prepareToEnterProcess(false);
+ item.mIntent.prepareToEnterProcess(false, source);
}
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bbb49fb..a436fa4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -31,6 +31,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.AppGlobals;
+import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -11439,7 +11440,7 @@
/**
* @hide
*/
- public void prepareToEnterProcess(boolean fromProtectedComponent) {
+ public void prepareToEnterProcess(boolean fromProtectedComponent, AttributionSource source) {
// We just entered destination process, so we should be able to read all
// parcelables inside.
setDefusable(true);
@@ -11447,10 +11448,10 @@
if (mSelector != null) {
// We can't recursively claim that this data is from a protected
// component, since it may have been filled in by a malicious app
- mSelector.prepareToEnterProcess(false);
+ mSelector.prepareToEnterProcess(false, source);
}
if (mClipData != null) {
- mClipData.prepareToEnterProcess();
+ mClipData.prepareToEnterProcess(source);
}
if (mContentUserHint != UserHandle.USER_CURRENT) {
@@ -11463,6 +11464,16 @@
if (fromProtectedComponent) {
mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
}
+
+ // Special attribution fix-up logic for any BluetoothDevice extras
+ // passed via Bluetooth intents
+ if (mAction != null && mAction.startsWith("android.bluetooth.")
+ && hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
+ final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device != null) {
+ device.prepareToEnterProcess(source);
+ }
+ }
}
/** @hide */
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index fbed907..03f6380 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -17,8 +17,8 @@
package android.content.pm;
import android.annotation.IntDef;
-import android.annotation.SuppressLint;
import android.annotation.TestApi;
+import android.app.Activity;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
@@ -1174,13 +1174,6 @@
*/
public WindowLayout windowLayout;
- /**
- * Attribution tags for finer grained calls if a {@link
- * android.content.Context#sendBroadcast(Intent, String)} is used with a permission.
- */
- @SuppressLint("MissingNullability")
- public String[] attributionTags;
-
public ActivityInfo() {
}
@@ -1209,7 +1202,6 @@
mMaxAspectRatio = orig.mMaxAspectRatio;
mMinAspectRatio = orig.mMinAspectRatio;
supportsSizeChanges = orig.supportsSizeChanges;
- attributionTags = orig.attributionTags;
}
/**
@@ -1532,15 +1524,6 @@
if (supportsSizeChanges) {
pw.println(prefix + "supportsSizeChanges=true");
}
- if (attributionTags != null && attributionTags.length > 0) {
- StringBuilder tags = new StringBuilder();
- tags.append(attributionTags[0]);
- for (int i = 1; i < attributionTags.length; i++) {
- tags.append(", ");
- tags.append(attributionTags[i]);
- }
- pw.println(prefix + "attributionTags=[" + tags + "]");
- }
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1586,7 +1569,6 @@
dest.writeFloat(mMaxAspectRatio);
dest.writeFloat(mMinAspectRatio);
dest.writeBoolean(supportsSizeChanges);
- dest.writeString8Array(attributionTags);
}
/**
@@ -1706,7 +1688,6 @@
mMaxAspectRatio = source.readFloat();
mMinAspectRatio = source.readFloat();
supportsSizeChanges = source.readBoolean();
- attributionTags = source.createString8Array();
}
/**
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index afaecec..63f93bf 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -92,7 +92,7 @@
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
- ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
@@ -108,7 +108,7 @@
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
- ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
@@ -124,7 +124,7 @@
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(
KEY_DISABLED_MESSAGE_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
@@ -170,7 +170,7 @@
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_IMPLICIT_RANK)
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_IMPLICIT_RANK)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
@@ -184,7 +184,7 @@
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_ICON_RES_ID)
+ ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_ICON_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index c67d00e..42847c8 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -16,8 +16,14 @@
package android.content.pm;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcel;
@@ -52,6 +58,25 @@
public String splitName;
/**
+ * Set of attribution tags that should be automatically applied to this
+ * component.
+ * <p>
+ * When this component represents an {@link Activity}, {@link Service},
+ * {@link ContentResolver} or {@link BroadcastReceiver}, each instance will
+ * be automatically configured with {@link Context#createAttributionContext}
+ * using the first attribution tag contained here.
+ * <p>
+ * Additionally, when this component represents a {@link BroadcastReceiver}
+ * and the sender of a broadcast requires the receiver to hold one or more
+ * specific permissions, those permission checks will be performed using
+ * each of the attributions tags contained here.
+ *
+ * @see Context#createAttributionContext(String)
+ */
+ @SuppressLint({"MissingNullability", "MutableBareField"})
+ public String[] attributionTags;
+
+ /**
* A string resource identifier (in the package's resources) containing
* a user-readable description of the component. From the "description"
* attribute or, if not set, 0.
@@ -87,6 +112,7 @@
applicationInfo = orig.applicationInfo;
processName = orig.processName;
splitName = orig.splitName;
+ attributionTags = orig.attributionTags;
descriptionRes = orig.descriptionRes;
enabled = orig.enabled;
exported = orig.exported;
@@ -172,6 +198,15 @@
if (splitName != null) {
pw.println(prefix + "splitName=" + splitName);
}
+ if (attributionTags != null && attributionTags.length > 0) {
+ StringBuilder tags = new StringBuilder();
+ tags.append(attributionTags[0]);
+ for (int i = 1; i < attributionTags.length; i++) {
+ tags.append(", ");
+ tags.append(attributionTags[i]);
+ }
+ pw.println(prefix + "attributionTags=[" + tags + "]");
+ }
pw.println(prefix + "enabled=" + enabled + " exported=" + exported
+ " directBootAware=" + directBootAware);
if (descriptionRes != 0) {
@@ -200,6 +235,7 @@
applicationInfo.writeToParcel(dest, parcelableFlags);
dest.writeString8(processName);
dest.writeString8(splitName);
+ dest.writeString8Array(attributionTags);
dest.writeInt(descriptionRes);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(exported ? 1 : 0);
@@ -211,6 +247,7 @@
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
processName = source.readString8();
splitName = source.readString8();
+ attributionTags = source.createString8Array();
descriptionRes = source.readInt();
enabled = (source.readInt() != 0);
exported = (source.readInt() != 0);
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index a9d70c5..d407b10 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -713,6 +713,7 @@
componentInfo.directBootAware = mainComponent.isDirectBootAware();
componentInfo.enabled = mainComponent.isEnabled();
componentInfo.splitName = mainComponent.getSplitName();
+ componentInfo.attributionTags = mainComponent.getAttributionTags();
}
private static void assignSharedFieldsForPackageItemInfo(
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 5d74e74..022ba16 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2816,15 +2816,7 @@
}
}
- @SuppressWarnings("AndroidFrameworkCompatChange")
private void convertSplitPermissions(ParsingPackage pkg) {
- // STOPSHIP(b/183905675): REMOVE THIS TERRIBLE, HORRIBLE, NO GOOD, VERY BAD HACK
- if ("com.android.chrome".equals(pkg.getPackageName())
- && pkg.getVersionCode() <= 445500399
- && pkg.getTargetSdkVersion() > Build.VERSION_CODES.R) {
- pkg.setTargetSdkVersion(Build.VERSION_CODES.R);
- }
-
final int listSize = mSplitPermissionInfos.size();
for (int is = 0; is < listSize; is++) {
final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is);
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 9285ccb..6f478ac 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -82,9 +82,6 @@
@Nullable
ActivityInfo.WindowLayout windowLayout;
- @Nullable
- String[] attributionTags;
-
public ParsedActivity(ParsedActivity other) {
super(other);
this.theme = other.theme;
@@ -110,7 +107,6 @@
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
this.windowLayout = other.windowLayout;
- this.attributionTags = other.attributionTags;
}
/**
@@ -176,7 +172,6 @@
alias.requestedVrComponent = target.requestedVrComponent;
alias.directBootAware = target.directBootAware;
alias.setProcessName(target.getProcessName());
- alias.attributionTags = target.attributionTags;
return alias;
// Not all attributes from the target ParsedActivity are copied to the alias.
@@ -304,7 +299,6 @@
} else {
dest.writeBoolean(false);
}
- dest.writeString8Array(this.attributionTags);
}
public ParsedActivity() {
@@ -338,7 +332,6 @@
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
}
- this.attributionTags = in.createString8Array();
}
public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
@@ -452,9 +445,4 @@
public ActivityInfo.WindowLayout getWindowLayout() {
return windowLayout;
}
-
- @Nullable
- public String[] getAttributionTags() {
- return attributionTags;
- }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index aa740bd..92a90e9 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -102,7 +102,8 @@
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_process,
R.styleable.AndroidManifestActivity_roundIcon,
- R.styleable.AndroidManifestActivity_splitName);
+ R.styleable.AndroidManifestActivity_splitName,
+ R.styleable.AndroidManifestActivity_attributionTags);
if (result.isError()) {
return result;
}
@@ -212,11 +213,6 @@
pkg.setVisibleToInstantApps(true);
}
- String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags);
- if (attributionTags != null) {
- activity.attributionTags = attributionTags.split("\\|");
- }
-
return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
false /*isAlias*/, visibleToEphemeral, input,
R.styleable.AndroidManifestActivity_parentActivityName,
@@ -281,7 +277,8 @@
R.styleable.AndroidManifestActivityAlias_name,
null /*processAttr*/,
R.styleable.AndroidManifestActivityAlias_roundIcon,
- null /*splitNameAttr*/);
+ null /*splitNameAttr*/,
+ R.styleable.AndroidManifestActivityAlias_attributionTags);
if (result.isError()) {
return result;
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
index a5e394d..033e30f 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
@@ -39,6 +39,8 @@
@Nullable
String splitName;
+ @Nullable
+ String[] attributionTags;
public ParsedMainComponent() {
}
@@ -51,6 +53,7 @@
this.exported = other.exported;
this.order = other.order;
this.splitName = other.splitName;
+ this.attributionTags = other.attributionTags;
}
public ParsedMainComponent setProcessName(String processName) {
@@ -84,6 +87,7 @@
dest.writeBoolean(this.exported);
dest.writeInt(this.order);
dest.writeString(this.splitName);
+ dest.writeString8Array(this.attributionTags);
}
protected ParsedMainComponent(Parcel in) {
@@ -94,6 +98,7 @@
this.exported = in.readBoolean();
this.order = in.readInt();
this.splitName = in.readString();
+ this.attributionTags = in.createString8Array();
}
public static final Parcelable.Creator<ParsedMainComponent> CREATOR =
@@ -135,6 +140,11 @@
return splitName;
}
+ @Nullable
+ public String[] getAttributionTags() {
+ return attributionTags;
+ }
+
public ParsedMainComponent setDirectBootAware(boolean value) {
directBootAware = value;
return this;
@@ -149,4 +159,9 @@
splitName = value;
return this;
}
+
+ public ParsedMainComponent setAttributionTags(@Nullable String[] value) {
+ attributionTags = value;
+ return this;
+ }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
index f70d62b..54bcbdd 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -48,7 +48,8 @@
TypedArray array, int flags, boolean useRoundIcon, ParseInput input,
int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr,
@Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr,
- @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr) {
+ @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr,
+ @Nullable Integer attributionTagsAttr) {
ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg,
array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr,
logoAttr, nameAttr, roundIconAttr);
@@ -94,6 +95,13 @@
component.splitName = array.getNonConfigurationString(splitNameAttr, 0);
}
+ if (attributionTagsAttr != null) {
+ final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0);
+ if (attributionTags != null) {
+ component.attributionTags = attributionTags.split("\\|");
+ }
+ }
+
return input.success(component);
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
index 4deab56..28fd919 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -74,7 +74,8 @@
R.styleable.AndroidManifestProvider_name,
R.styleable.AndroidManifestProvider_process,
R.styleable.AndroidManifestProvider_roundIcon,
- R.styleable.AndroidManifestProvider_splitName);
+ R.styleable.AndroidManifestProvider_splitName,
+ R.styleable.AndroidManifestProvider_attributionTags);
if (result.isError()) {
return result;
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
index 739bee2..ae107ce 100644
--- a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
@@ -68,7 +68,8 @@
R.styleable.AndroidManifestService_name,
R.styleable.AndroidManifestService_process,
R.styleable.AndroidManifestService_roundIcon,
- R.styleable.AndroidManifestService_splitName
+ R.styleable.AndroidManifestService_splitName,
+ R.styleable.AndroidManifestService_attributionTags
);
if (result.isError()) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 7ebb646..d8050ed 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -34,6 +34,8 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
+import android.net.ConnectivityAnnotations.MultipathPreference;
+import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.os.Build;
@@ -463,6 +465,7 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ @RestrictBackgroundStatus
public int getRestrictBackgroundStatus(int uid) {
try {
return mService.getRestrictBackgroundStatus(uid);
@@ -588,6 +591,7 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ @MultipathPreference
public int getMultipathPreference(@NonNull Network network) {
try {
return mService.getMultipathPreference(network);
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
index 1f18184..25a2574 100644
--- a/core/java/android/net/vcn/VcnTransportInfo.java
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -16,11 +16,12 @@
package android.net.vcn;
-import static android.net.NetworkCapabilities.REDACT_NONE;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
import android.net.TransportInfo;
import android.net.wifi.WifiInfo;
import android.os.Parcel;
@@ -108,13 +109,24 @@
@Override
@NonNull
public TransportInfo makeCopy(long redactions) {
+ if ((redactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) != 0) {
+ return new VcnTransportInfo(null, INVALID_SUBSCRIPTION_ID);
+ }
+
return new VcnTransportInfo(
(mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId);
}
@Override
public long getApplicableRedactions() {
- return (mWifiInfo == null) ? REDACT_NONE : mWifiInfo.getApplicableRedactions();
+ long redactions = REDACT_FOR_NETWORK_SETTINGS;
+
+ // Add additional wifi redactions if necessary
+ if (mWifiInfo != null) {
+ redactions |= mWifiInfo.getApplicableRedactions();
+ }
+
+ return redactions;
}
/** {@inheritDoc} */
@@ -135,6 +147,14 @@
public VcnTransportInfo createFromParcel(Parcel in) {
final int subId = in.readInt();
final WifiInfo wifiInfo = in.readParcelable(null);
+
+ // If all fields are their null values, return null TransportInfo to avoid
+ // leaking information about this being a VCN Network (instead of macro
+ // cellular, etc)
+ if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) {
+ return null;
+ }
+
return new VcnTransportInfo(wifiInfo, subId);
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 6e99b0d..dfd935d0 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -67,3 +67,6 @@
# RecoverySystem
per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS
+
+# Bugreporting
+per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 1092adf..3daa3a5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -31,6 +31,7 @@
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.Uri;
+import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.Settings.ResetMode;
import android.util.ArrayMap;
import android.util.Log;
@@ -585,8 +586,16 @@
*
* @hide
*/
+ @TestApi
public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
+ /**
+ * Trace error logger properties definitions.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_TRACE_ERROR_LOGGER = "trace_error_logger";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
@@ -839,6 +848,37 @@
}
/**
+ * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
+ * config values. This is intended for use during tests to prevent a sync operation clearing
+ * config values, which could influence the outcome of the tests, i.e. by changing behavior.
+ *
+ * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
+ * {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
+ * Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
+ *
+ * @see #isSyncDisabled()
+ * @hide
+ */
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static void setSyncDisabled(@SyncDisabledMode int syncDisabledMode) {
+ ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
+ Settings.Config.setSyncDisabled(contentResolver, syncDisabledMode);
+ }
+
+ /**
+ * Returns the current state of sync disabling, {@code true} when disabled, {@code false}
+ * otherwise.
+ *
+ * @see #setSyncDisabled(int)
+ * @hide
+ */
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static boolean isSyncDisabled() {
+ ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
+ return Settings.Config.isSyncDisabled(contentResolver);
+ }
+
+ /**
* Add a listener for property changes.
* <p>
* This listener will be called whenever properties in the specified namespace change. Callbacks
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e410e50..b948ce2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -267,8 +267,40 @@
/** @hide */
public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+ /**
+ * The return values for {@link Settings.Config#set}
+ * @hide
+ */
+ @IntDef(prefix = "SET_ALL_RESULT_",
+ value = { SET_ALL_RESULT_FAILURE, SET_ALL_RESULT_SUCCESS, SET_ALL_RESULT_DISABLED })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface SetAllResult {}
+
+ /**
+ * A return value for {@link #KEY_CONFIG_SET_ALL_RETURN}, indicates failure.
+ * @hide
+ */
+ public static final int SET_ALL_RESULT_FAILURE = 0;
+
+ /**
+ * A return value for {@link #KEY_CONFIG_SET_ALL_RETURN}, indicates success.
+ * @hide
+ */
+ public static final int SET_ALL_RESULT_SUCCESS = 1;
+
+ /**
+ * A return value for {@link #KEY_CONFIG_SET_ALL_RETURN}, indicates a set all is disabled.
+ * @hide
+ */
+ public static final int SET_ALL_RESULT_DISABLED = 2;
+
/** @hide */
- public static final String KEY_CONFIG_SET_RETURN = "config_set_return";
+ public static final String KEY_CONFIG_SET_ALL_RETURN = "config_set_all_return";
+
+ /** @hide */
+ public static final String KEY_CONFIG_IS_SYNC_DISABLED_RETURN =
+ "config_is_sync_disabled_return";
/**
* An int extra specifying a subscription ID.
@@ -890,6 +922,21 @@
"android.settings.LOCALE_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of lockscreen.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_LOCKSCREEN_SETTINGS = "android.settings.LOCK_SCREEN_SETTINGS";
+
+ /**
* Activity Action: Show settings to configure input methods, in particular
* allowing the user to enable input methods.
* <p>
@@ -2324,6 +2371,11 @@
public static final String CALL_METHOD_PREFIX_KEY = "_prefix";
/**
+ * @hide - String argument extra to the fast-path call()-based requests
+ */
+ public static final String CALL_METHOD_SYNC_DISABLED_MODE_KEY = "_disabled_mode";
+
+ /**
* @hide - RemoteCallback monitor callback argument extra to the fast-path call()-based requests
*/
public static final String CALL_METHOD_MONITOR_CALLBACK_KEY = "_monitor_callback_key";
@@ -2386,6 +2438,15 @@
/** @hide - Private call() method to reset to defaults the 'configuration' table */
public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+ /** @hide - Private call() method to disable / re-enable syncs to the 'configuration' table */
+ public static final String CALL_METHOD_SET_SYNC_DISABLED_CONFIG = "SET_SYNC_DISABLED_config";
+
+ /**
+ * @hide - Private call() method to return whether syncs are disabled for the 'configuration'
+ * table
+ */
+ public static final String CALL_METHOD_IS_SYNC_DISABLED_CONFIG = "IS_SYNC_DISABLED_config";
+
/** @hide - Private call() method to register monitor callback for 'configuration' table */
public static final String CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG =
"REGISTER_MONITOR_CALLBACK_config";
@@ -2762,11 +2823,11 @@
return true;
}
- public boolean setStringsForPrefix(ContentResolver cr, String prefix,
+ public @SetAllResult int setStringsForPrefix(ContentResolver cr, String prefix,
HashMap<String, String> keyValues) {
if (mCallSetAllCommand == null) {
// This NameValueCache does not support atomically setting multiple flags
- return false;
+ return SET_ALL_RESULT_FAILURE;
}
try {
Bundle args = new Bundle();
@@ -2776,10 +2837,10 @@
Bundle bundle = cp.call(cr.getAttributionSource(),
mProviderHolder.mUri.getAuthority(),
mCallSetAllCommand, null, args);
- return bundle.getBoolean(KEY_CONFIG_SET_RETURN);
+ return bundle.getInt(KEY_CONFIG_SET_ALL_RETURN);
} catch (RemoteException e) {
// Not supported by the remote side
- return false;
+ return SET_ALL_RESULT_FAILURE;
}
}
@@ -9985,6 +10046,12 @@
@Readable
public static final String NAS_SETTINGS_UPDATED = "nas_settings_updated";
+ /**
+ * Control whether Game Dashboard shortcut is always on for all games.
+ * @hide
+ */
+ @Readable
+ public static final String GAME_DASHBOARD_ALWAYS_ON = "game_dashboard_always_on";
/**
* These entries are considered common between the personal and the managed profile,
@@ -14199,6 +14266,15 @@
public static final String ARE_USER_DISABLED_HDR_FORMATS_ALLOWED =
"are_user_disabled_hdr_formats_allowed";
+ /**
+ * Whether or not syncs (bulk set operations) for {@link DeviceConfig} are disabled
+ * currently. The value is boolean (1 or 0). The value '1' means that {@link
+ * DeviceConfig#setProperties(DeviceConfig.Properties)} will return {@code false}.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_SYNC_DISABLED = "device_config_sync_disabled";
+
/** @hide */ public static String zenModeToString(int mode) {
if (mode == ZEN_MODE_IMPORTANT_INTERRUPTIONS) return "ZEN_MODE_IMPORTANT_INTERRUPTIONS";
if (mode == ZEN_MODE_ALARMS) return "ZEN_MODE_ALARMS";
@@ -16033,6 +16109,39 @@
* @hide
*/
public static final class Config extends NameValueTable {
+
+ /**
+ * The modes that can be used when disabling syncs to the 'config' settings.
+ * @hide
+ */
+ @IntDef(prefix = "DISABLE_SYNC_MODE_",
+ value = { SYNC_DISABLED_MODE_NONE, SYNC_DISABLED_MODE_PERSISTENT,
+ SYNC_DISABLED_MODE_UNTIL_REBOOT })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface SyncDisabledMode {}
+
+ /**
+ * Sync is not not disabled.
+ *
+ * @hide
+ */
+ public static final int SYNC_DISABLED_MODE_NONE = 0;
+
+ /**
+ * Disabling of Config bulk update / syncing is persistent, i.e. it survives a device
+ * reboot.
+ * @hide
+ */
+ public static final int SYNC_DISABLED_MODE_PERSISTENT = 1;
+
+ /**
+ * Disabling of Config bulk update / syncing is not persistent, i.e. it will not survive a
+ * device reboot.
+ * @hide
+ */
+ public static final int SYNC_DISABLED_MODE_UNTIL_REBOOT = 2;
+
private static final ContentProviderHolder sProviderHolder =
new ContentProviderHolder(DeviceConfig.CONTENT_URI);
@@ -16125,7 +16234,7 @@
* @param resolver to access the database with.
* @param namespace to which the names should be set.
* @param keyValues map of key names (without the prefix) to values.
- * @return
+ * @return true if the name/value pairs were set, false if setting was blocked
*
* @hide
*/
@@ -16138,12 +16247,15 @@
compositeKeyValueMap.put(
createCompositeName(namespace, entry.getKey()), entry.getValue());
}
- // If can't set given configuration that means it's bad
- if (!sNameValueCache.setStringsForPrefix(resolver, createPrefix(namespace),
- compositeKeyValueMap)) {
- throw new DeviceConfig.BadConfigException();
+ int result = sNameValueCache.setStringsForPrefix(
+ resolver, createPrefix(namespace), compositeKeyValueMap);
+ if (result == SET_ALL_RESULT_SUCCESS) {
+ return true;
+ } else if (result == SET_ALL_RESULT_DISABLED) {
+ return false;
}
- return true;
+ // If can't set given configuration that means it's bad
+ throw new DeviceConfig.BadConfigException();
}
/**
@@ -16179,6 +16291,50 @@
}
/**
+ * Bridge method between {@link DeviceConfig#setSyncDisabled(int)} and the
+ * {@link com.android.providers.settings.SettingsProvider} implementation.
+ *
+ * @hide
+ */
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
+ static void setSyncDisabled(
+ @NonNull ContentResolver resolver, @SyncDisabledMode int disableSyncMode) {
+ try {
+ Bundle args = new Bundle();
+ args.putInt(CALL_METHOD_SYNC_DISABLED_MODE_KEY, disableSyncMode);
+ IContentProvider cp = sProviderHolder.getProvider(resolver);
+ cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(), CALL_METHOD_SET_SYNC_DISABLED_CONFIG,
+ null, args);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't set sync disabled " + DeviceConfig.CONTENT_URI, e);
+ }
+ }
+
+ /**
+ * Bridge method between {@link DeviceConfig#isSyncDisabled()} and the
+ * {@link com.android.providers.settings.SettingsProvider} implementation.
+ *
+ * @hide
+ */
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
+ static boolean isSyncDisabled(@NonNull ContentResolver resolver) {
+ try {
+ Bundle args = Bundle.EMPTY;
+ IContentProvider cp = sProviderHolder.getProvider(resolver);
+ Bundle bundle = cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(), CALL_METHOD_IS_SYNC_DISABLED_CONFIG,
+ null, args);
+ return bundle.getBoolean(KEY_CONFIG_IS_SYNC_DISABLED_RETURN);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't query sync disabled " + DeviceConfig.CONTENT_URI, e);
+ }
+ return false;
+ }
+
+ /**
* Register callback for monitoring Config table.
*
* @param resolver Handle to the content resolver.
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index 9d0b582..2e4af3f 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -61,6 +61,7 @@
public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, ServiceConnection {
private static final String TAG = "QAWalletSClient";
+ public static final String SETTING_KEY = "lockscreen_show_wallet";
private final Handler mHandler;
private final Context mContext;
private final Queue<ApiCaller> mRequestQueue;
@@ -96,13 +97,12 @@
int currentUser = ActivityManager.getCurrentUser();
return currentUser == UserHandle.USER_SYSTEM
&& checkUserSetupComplete()
- && checkSecureSetting(Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED)
&& !new LockPatternUtils(mContext).isUserInLockdown(currentUser);
}
@Override
public boolean isWalletFeatureAvailableWhenDeviceLocked() {
- return checkSecureSetting(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT);
+ return checkSecureSetting(SETTING_KEY);
}
@Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 572e50a..c9a7949 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -72,7 +72,7 @@
DEFAULT_FLAGS.put("settings_contextual_home", "false");
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "true");
DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true");
- DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "false");
+ DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 7125232..6a2b723 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.view.IRemoteAnimationFinishedCallback;
+import android.view.SurfaceControl;
import android.graphics.GraphicBuffer;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
@@ -43,9 +44,10 @@
* updated accordingly. This should be called before `finish`
* @param taskId for which the leash should be updated
* @param finishTransaction leash operations for the final transform.
+ * @param overlay the surface control for an overlay being shown above the pip (can be null)
*/
void setFinishTaskTransaction(int taskId,
- in PictureInPictureSurfaceTransaction finishTransaction);
+ in PictureInPictureSurfaceTransaction finishTransaction, in SurfaceControl overlay);
/**
* Notifies to the system that the animation into Recents should end, and all leashes associated
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4647f47..679da31 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3581,7 +3581,9 @@
}
structure.setChildCount(childrenCount);
- ArrayList<View> preorderedList = buildOrderedChildList();
+ ArrayList<View> tempPreorderedList = buildOrderedChildList();
+ ArrayList<View> preorderedList =
+ tempPreorderedList != null ? new ArrayList<>(tempPreorderedList) : null;
boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bf8785a..9bbd5dd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1201,8 +1201,7 @@
Looper.myLooper());
if (mAttachInfo.mThreadedRenderer != null) {
- InputMetricsListener listener =
- new InputMetricsListener(mInputEventReceiver);
+ InputMetricsListener listener = new InputMetricsListener();
mHardwareRendererObserver = new HardwareRendererObserver(
listener, listener.data, mHandler, true /*waitForPresentTime*/);
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
@@ -1414,6 +1413,9 @@
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
+ if (mHardwareRendererObserver != null) {
+ mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
+ }
}
}
}
@@ -7505,7 +7507,8 @@
final View prevDragView = mCurrentDragView;
if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
- event.mClipData.prepareToEnterProcess();
+ event.mClipData.prepareToEnterProcess(
+ mView.getContext().getAttributionSource());
}
// Now dispatch the drag/drop event
@@ -8117,6 +8120,9 @@
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
if (hardwareRenderer != null) {
+ if (mHardwareRendererObserver != null) {
+ hardwareRenderer.removeObserver(mHardwareRendererObserver);
+ }
if (mView != null) {
hardwareRenderer.destroyHardwareResources(mView);
}
@@ -8618,18 +8624,12 @@
super.dispose();
}
}
- WindowInputEventReceiver mInputEventReceiver;
+ private WindowInputEventReceiver mInputEventReceiver;
final class InputMetricsListener
implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
- private InputEventReceiver mReceiver;
-
- InputMetricsListener(InputEventReceiver receiver) {
- mReceiver = receiver;
- }
-
@Override
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
@@ -8642,6 +8642,20 @@
// available, we cannot compute end-to-end input latency metrics.
return;
}
+ final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
+ if (mInputEventReceiver == null) {
+ return;
+ }
+ if (gpuCompletedTime >= presentTime) {
+ final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6;
+ final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
+ Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs
+ + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId
+ + ", INPUT_EVENT_ID=" + inputEventId);
+ // TODO(b/186664409): figure out why this sometimes happens
+ return;
+ }
+ mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
}
}
HardwareRendererObserver mHardwareRendererObserver;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5fb4e70..1499acec 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1354,6 +1354,11 @@
public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
}
+ /** @hide */
+ public boolean decorFitsSystemWindows() {
+ return false;
+ }
+
/**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index c26b302..9b463bb 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -638,10 +638,11 @@
}
/**
- * Return {@code true} if this input method should be shown in the IME picker.
- * @hide
+ * Returns {@code true} if this input method should be shown in menus for selecting an Input
+ * Method, such as the system Input Method Picker. This is {@code false} if the IME is intended
+ * to be accessed programmatically.
*/
- public boolean showInInputMethodPicker() {
+ public boolean shouldShowInInputMethodPicker() {
return mShowInInputMethodPicker;
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 53e145e..ec07209 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -259,6 +259,11 @@
}
mCurrentDate.set(Calendar.YEAR, year);
+ if (mCurrentDate.compareTo(mMinDate) < 0) {
+ mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+ } else if (mCurrentDate.compareTo(mMaxDate) > 0) {
+ mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+ }
onDateChanged(true, true);
// Automatically switch to day picker.
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 8debe5d..d67fb32 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -17,6 +17,8 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -40,11 +42,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.widget.FrameLayout;
import com.android.internal.R;
import com.android.internal.policy.DecorView;
+import com.android.internal.util.ContrastColorUtil;
import java.time.Duration;
import java.time.Instant;
@@ -69,6 +73,12 @@
private static final String TAG = SplashScreenView.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final int LIGHT_BARS_MASK =
+ WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
+ | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+ private static final int WINDOW_FLAG_MASK = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
+ | FLAG_TRANSLUCENT_NAVIGATION | FLAG_TRANSLUCENT_STATUS;
+
private boolean mNotCopyable;
private boolean mRevealAnimationSupported = true;
private int mInitBackgroundColor;
@@ -84,10 +94,14 @@
private Activity mHostActivity;
// cache original window and status
private Window mWindow;
- private boolean mDrawBarBackground;
+ private int mAppWindowFlags;
private int mStatusBarColor;
private int mNavigationBarColor;
+ private int mSystemBarsAppearance;
private boolean mHasRemoved;
+ private boolean mNavigationContrastEnforced;
+ private boolean mStatusContrastEnforced;
+ private boolean mDecorFitsSystemWindows;
/**
* Internal builder to create a SplashScreenView object.
@@ -347,54 +361,63 @@
mWindow = null;
}
if (mHostActivity != null) {
- mHostActivity.detachSplashScreenView();
+ mHostActivity.setSplashScreenView(null);
+ mHostActivity = null;
}
mHasRemoved = true;
}
/**
- * Called when this view is attached to an activity.
+ * Called when this view is attached to an activity. This also makes SystemUI colors
+ * transparent so the content of splash screen view can draw fully.
* @hide
*/
- public void attachHostActivity(Activity activity) {
+ public void attachHostActivityAndSetSystemUIColors(Activity activity, Window window) {
+ activity.setSplashScreenView(this);
mHostActivity = activity;
- }
-
- /**
- * Cache the root window.
- * @hide
- */
- public void cacheRootWindow(Window window) {
mWindow = window;
+ final WindowManager.LayoutParams attr = window.getAttributes();
+ mAppWindowFlags = attr.flags;
+ mStatusBarColor = window.getStatusBarColor();
+ mNavigationBarColor = window.getNavigationBarColor();
+ mSystemBarsAppearance = window.getInsetsController().getSystemBarsAppearance();
+ mNavigationContrastEnforced = window.isNavigationBarContrastEnforced();
+ mStatusContrastEnforced = window.isStatusBarContrastEnforced();
+ mDecorFitsSystemWindows = window.decorFitsSystemWindows();
+
+ applySystemBarsContrastColor(window.getInsetsController(), mInitBackgroundColor);
+ // Let app draw the background of bars.
+ window.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ // Use specified bar colors instead of window background.
+ window.clearFlags(FLAG_TRANSLUCENT_STATUS | FLAG_TRANSLUCENT_NAVIGATION);
+ window.setStatusBarColor(Color.TRANSPARENT);
+ window.setNavigationBarColor(Color.TRANSPARENT);
+ window.setDecorFitsSystemWindows(false);
+ window.setStatusBarContrastEnforced(false);
+ window.setNavigationBarContrastEnforced(false);
+ }
+
+ /** Called when this view is removed from the host activity. */
+ private void restoreSystemUIColors() {
+ mWindow.setFlags(mAppWindowFlags, WINDOW_FLAG_MASK);
+ mWindow.setStatusBarColor(mStatusBarColor);
+ mWindow.setNavigationBarColor(mNavigationBarColor);
+ mWindow.getInsetsController().setSystemBarsAppearance(mSystemBarsAppearance,
+ LIGHT_BARS_MASK);
+ mWindow.setDecorFitsSystemWindows(mDecorFitsSystemWindows);
+ mWindow.setStatusBarContrastEnforced(mStatusContrastEnforced);
+ mWindow.setNavigationBarContrastEnforced(mNavigationContrastEnforced);
}
/**
- * Called after SplashScreenView has added on the root window.
+ * Makes the icon color of system bars contrast.
* @hide
*/
- public void makeSystemUIColorsTransparent() {
- if (mWindow != null) {
- final WindowManager.LayoutParams attr = mWindow.getAttributes();
- mDrawBarBackground = (attr.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
- mWindow.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- mStatusBarColor = mWindow.getStatusBarColor();
- mNavigationBarColor = mWindow.getNavigationBarDividerColor();
- mWindow.setStatusBarColor(Color.TRANSPARENT);
- mWindow.setNavigationBarColor(Color.TRANSPARENT);
- }
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
-
- private void restoreSystemUIColors() {
- if (mWindow != null) {
- if (!mDrawBarBackground) {
- mWindow.clearFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- }
- mWindow.setStatusBarColor(mStatusBarColor);
- mWindow.setNavigationBarColor(mNavigationBarColor);
- }
+ public static void applySystemBarsContrastColor(WindowInsetsController windowInsetsController,
+ int backgroundColor) {
+ final int lightBarAppearance = ContrastColorUtil.isColorLight(backgroundColor)
+ ? LIGHT_BARS_MASK : 0;
+ windowInsetsController.setSystemBarsAppearance(lightBarAppearance, LIGHT_BARS_MASK);
}
/**
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 281702e..3cf4621 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -92,7 +92,7 @@
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
- void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages);
+ void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in Map<String, String[]> excludedPackageTags);
void removeUser(int userHandle);
void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
@@ -113,7 +113,7 @@
void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback);
List<AsyncNotedAppOp> extractAsyncOps(String packageName);
- int checkOperationRaw(int code, int uid, String packageName);
+ int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag);
void reloadNonHistoricalState();
diff --git a/core/java/com/android/internal/app/procstats/OWNERS b/core/java/com/android/internal/app/procstats/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 0441594..f029e6a 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -28,6 +28,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
@@ -144,6 +145,7 @@
public static final int CUJ_LOCKSCREEN_TRANSITION_TO_AOD = 24;
public static final int CUJ_LAUNCHER_OPEN_ALL_APPS = 25;
public static final int CUJ_LAUNCHER_ALL_APPS_SCROLL = 26;
+ public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET = 27;
private static final int NO_STATSD_LOGGING = -1;
@@ -179,6 +181,7 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET,
};
private static volatile InteractionJankMonitor sInstance;
@@ -225,6 +228,7 @@
CUJ_LOCKSCREEN_TRANSITION_TO_AOD,
CUJ_LAUNCHER_OPEN_ALL_APPS,
CUJ_LAUNCHER_ALL_APPS_SCROLL,
+ CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -537,6 +541,8 @@
return "CUJ_LAUNCHER_OPEN_ALL_APPS";
case CUJ_LAUNCHER_ALL_APPS_SCROLL:
return "CUJ_LAUNCHER_ALL_APPS_SCROLL";
+ case CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET:
+ return "LAUNCHER_APP_LAUNCH_FROM_WIDGET";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java
index 0690d1f..8178529 100644
--- a/core/java/com/android/internal/os/BatteryChargeCalculator.java
+++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java
@@ -63,10 +63,15 @@
builder.setChargeTimeRemainingMs(chargeTimeRemainingMs / 1000);
}
+ long dischargeMah = batteryStats.getUahDischarge(BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ if (dischargeMah == 0) {
+ dischargeMah = (long) ((dischargedPowerLowerBoundMah + dischargedPowerUpperBoundMah) / 2
+ + 0.5);
+ }
+
builder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
- .setConsumedPower(
- (dischargedPowerLowerBoundMah + dischargedPowerUpperBoundMah) / 2);
+ .setConsumedPower(dischargeMah);
}
@Override
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f597e50..0938c85 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -13120,13 +13120,11 @@
if (Process.isIsolated(uid)) {
// This could happen if the isolated uid mapping was removed before that process
// was actually killed.
- mCpuUidUserSysTimeReader.removeUid(uid);
if (DEBUG) Slog.d(TAG, "Got readings for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.d(TAG, "Got readings for an invalid user's uid " + uid);
- mCpuUidUserSysTimeReader.removeUid(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
@@ -13231,19 +13229,16 @@
mWakeLockAllocationsUs = null;
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final List<Integer> uidsToRemove = new ArrayList<>();
// If power is being accumulated for attribution, data needs to be read immediately.
final boolean forceRead = powerAccumulator != null;
mCpuUidFreqTimeReader.readDelta(forceRead, (uid, cpuFreqTimeMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- uidsToRemove.add(uid);
if (DEBUG) Slog.d(TAG, "Got freq readings for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.d(TAG, "Got freq readings for an invalid user's uid " + uid);
- uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
@@ -13307,9 +13302,6 @@
}
}
});
- for (int uid : uidsToRemove) {
- mCpuUidFreqTimeReader.removeUid(uid);
- }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
@@ -13361,25 +13353,19 @@
public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final List<Integer> uidsToRemove = new ArrayList<>();
mCpuUidActiveTimeReader.readDelta(false, (uid, cpuActiveTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- uidsToRemove.add(uid);
if (DEBUG) Slog.w(TAG, "Got active times for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.w(TAG, "Got active times for an invalid user's uid " + uid);
- uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery);
});
- for (int uid : uidsToRemove) {
- mCpuUidActiveTimeReader.removeUid(uid);
- }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
@@ -13400,19 +13386,16 @@
@Nullable CpuDeltaPowerAccumulator powerAccumulator) {
final long startTimeMs = mClocks.uptimeMillis();
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final List<Integer> uidsToRemove = new ArrayList<>();
// If power is being accumulated for attribution, data needs to be read immediately.
final boolean forceRead = powerAccumulator != null;
mCpuUidClusterTimeReader.readDelta(forceRead, (uid, cpuClusterTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
- uidsToRemove.add(uid);
if (DEBUG) Slog.w(TAG, "Got cluster times for an isolated uid: " + uid);
return;
}
if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
if (DEBUG) Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid);
- uidsToRemove.add(uid);
return;
}
final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
@@ -13422,9 +13405,6 @@
powerAccumulator.addCpuClusterDurationsMs(u, cpuClusterTimesMs);
}
});
- for (int uid : uidsToRemove) {
- mCpuUidClusterTimeReader.removeUid(uid);
- }
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 0ea299d..1a23cc1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3931,6 +3931,11 @@
applyDecorFitsSystemWindows();
}
+ @Override
+ public boolean decorFitsSystemWindows() {
+ return mDecorFitsSystemWindows;
+ }
+
private void applyDecorFitsSystemWindows() {
ViewRootImpl impl = getViewRootImplOrNull();
if (impl != null) {
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 44597cc..a699f91 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -241,13 +241,13 @@
}
// Some other error. Give up
- ALOGW("Failed to send outbound event on channel '%s'. status=%d",
- getInputChannelName().c_str(), status);
+ ALOGW("Failed to send outbound event on channel '%s'. status=%s(%d)",
+ getInputChannelName().c_str(), statusToString(status).c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
std::string message =
- android::base::StringPrintf("Failed to send outbound event. status=%d",
- status);
+ android::base::StringPrintf("Failed to send outbound event. status=%s(%d)",
+ statusToString(status).c_str(), status);
jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
@@ -319,8 +319,8 @@
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (status != OK && status != WOULD_BLOCK) {
- ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
- getInputChannelName().c_str(), status);
+ ALOGE("channel '%s' ~ Failed to consume input event. status=%s(%d)",
+ getInputChannelName().c_str(), statusToString(status).c_str(), status);
return status;
}
@@ -502,9 +502,9 @@
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
- std::string message =
- android::base::StringPrintf("Failed to initialize input event receiver. status=%d",
- status);
+ std::string message = android::base::
+ StringPrintf("Failed to initialize input event receiver. status=%s(%d)",
+ statusToString(status).c_str(), status);
jniThrowRuntimeException(env, message.c_str());
return 0;
}
@@ -531,7 +531,7 @@
if (status != DEAD_OBJECT) {
std::string message =
android::base::StringPrintf("Failed to finish input event. status=%s(%d)",
- strerror(-status), status);
+ statusToString(status).c_str(), status);
jniThrowRuntimeException(env, message.c_str());
}
}
@@ -564,8 +564,8 @@
&consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
std::string message =
- android::base::StringPrintf("Failed to consume batched input event. status=%d",
- status);
+ android::base::StringPrintf("Failed to consume batched input event. status=%s(%d)",
+ statusToString(status).c_str(), status);
jniThrowRuntimeException(env, message.c_str());
return JNI_FALSE;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8df113d..4a1a272 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -826,7 +826,7 @@
PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
- bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, true);
+ bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);
if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 24fef48..5fe96ed 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -402,7 +402,7 @@
socklen_t cred_size = sizeof credentials;
if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
|| cred_size != sizeof credentials) {
- fail_fn_1("ForkMany failed to get initial credentials, %s", strerror(errno));
+ fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno)));
}
bool first_time = true;
@@ -453,7 +453,7 @@
close(session_socket);
int new_fd = accept(zygote_socket_fd, nullptr, nullptr);
if (new_fd == -1) {
- fail_fn_z("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno));
+ fail_fn_z(CREATE_ERROR("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno)));
}
if (new_fd != session_socket) {
// Move new_fd back to the old value, so that we don't have to change Java-level data
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index b157146..fa1e9d4 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -221,6 +221,9 @@
optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
repeated DisplayAreaChildProto children = 3 [deprecated=true];
optional bool is_task_display_area = 4;
+ optional bool is_root_display_area = 5;
+ optional int32 feature_id = 6;
+ optional bool is_organized = 7;
}
/* represents a generic child of a DisplayArea */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 50fb01b..3d892b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2898,12 +2898,6 @@
android:description="@string/permdesc_runInBackground"
android:protectionLevel="normal" />
- <!-- Allows a companion app to start a foreground service from the background.
- {@see android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
- -->
- <permission android:name="android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND"
- android:protectionLevel="normal"/>
-
<!-- Allows a companion app to use data in the background.
<p>Protection level: normal
-->
@@ -5772,6 +5766,21 @@
android:protectionLevel="normal" />
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/>
+ <!-- Allows an application to take screenshots of layers that normally would be blacked out when
+ a screenshot is taken. Specifically, layers that have the flag
+ {@link android.view.SurfaceControl#SECURE} will be screenshot if the caller requests to
+ capture secure layers. Normally those layers will be rendered black.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to query over global data in AppSearch.
+ @hide -->
+ <permission android:name="android.permission.READ_GLOBAL_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 9d739b9..7a8da36 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -1,6 +1,7 @@
adamp@google.com
alanv@google.com
asc@google.com
+cinek@google.com
dsandler@android.com
dsandler@google.com
dupin@google.com
@@ -8,6 +9,7 @@
hackbod@google.com
ilyamaty@google.com
jaggies@google.com
+jdemeulenaere@google.com
jsharkey@android.com
jsharkey@google.com
juliacr@google.com
@@ -17,7 +19,9 @@
narayan@google.com
ogunwale@google.com
patb@google.com
+shanh@google.com
svetoslavganov@android.com
svetoslavganov@google.com
toddke@google.com
+tsuji@google.com
yamasani@google.com
diff --git a/core/res/res/drawable/work_widget_mask_view_background.xml b/core/res/res/drawable/work_widget_mask_view_background.xml
new file mode 100644
index 0000000..ce9c514
--- /dev/null
+++ b/core/res/res/drawable/work_widget_mask_view_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="?android:attr/colorSurfaceVariant" />
+ <corners android:radius="@dimen/system_app_widget_background_radius" />
+</shape>
diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml
index e7174cc..86c5d13 100644
--- a/core/res/res/layout/work_widget_mask_view.xml
+++ b/core/res/res/layout/work_widget_mask_view.xml
@@ -18,14 +18,14 @@
android:id="@+id/work_widget_mask_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?android:attr/colorSurfaceVariant"
+ android:background="@drawable/work_widget_mask_view_background"
android:importantForAccessibility="noHideDescendants"
android:clickable="true">
<com.android.internal.widget.DisableImageView
android:id="@+id/work_widget_app_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="center"
android:clickable="false" />
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2fffaa6..4940b80 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"እንደገና ሞክር"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"እንደገና ሞክር"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"ለሁሉም ባህሪያት እና ውሂብ ያስከፍቱ"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"የመጨረሻውን የገጽ ክፈት ሙከራዎችን አልፏል"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"የመጨረሻውን በመልክ መክፈት ሙከራዎችን አልፏል"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ምንም ሲም ካርድ የለም"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"በጡባዊ ውስጥ ምንም SIM ካርድ የለም።"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"በእርስዎ Android TV መሣሪያ ላይ ምንም ሲም ካርድ የለም።"</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"የመክፈቻ አካባቢውን አስፋፋ።"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"በማንሸራተት ክፈት።"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"በስርዓተ-ጥለት መክፈት።"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"በፊት መክፈት።"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"በመልክ መክፈት።"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"በፒን መክፈት።"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"የሲም ፒን ክፈት።"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"የሲም PUK ክፈት።"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 74f98fc..1392510 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1869,10 +1869,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
- <skip />
- <!-- no translation found for battery_saver_description (8518809702138617167) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ সীমিত অথবা অফ কৰে।\n\n"<annotation id="url">"অধিক জানক"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ অফ কৰে অথবা সীমাবদ্ধ কৰে।"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰৰ হ্ৰাস কৰিবলৈ ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা এক্সেছ কৰিব পাৰে, কিন্তু সঘনাই এক্সেছ কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ উদাহৰণস্বৰূপে এয়া হ\'ব পাৰে যে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"অন কৰক"</string>
@@ -1975,10 +1973,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"অধিক জানক"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"এপ্ আনপজ কৰক"</string>
- <!-- no translation found for work_mode_off_title (961171256005852058) -->
- <skip />
- <!-- no translation found for work_mode_off_message (7319580997683623309) -->
- <skip />
+ <string name="work_mode_off_title" msgid="961171256005852058">"কাম সম্পৰ্কীয় এপ্ অন কৰিবনে?"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"আপোনাৰ কাম সম্পৰ্কীয় এপ্ আৰু জাননীৰ এক্সেছ পাওক"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 66ce6bd..5597cd0 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1869,10 +1869,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
- <skip />
- <!-- no translation found for battery_saver_description (8518809702138617167) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"চালু করুন"</string>
@@ -1975,10 +1973,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> এখন উপলভ্য নয়। এই অ্যাপটিকে <xliff:g id="APP_NAME_1">%2$s</xliff:g> অ্যাপ ম্যানেজ করে।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"আরও জানুন"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"অ্যাপ আবার চালু করুন"</string>
- <!-- no translation found for work_mode_off_title (961171256005852058) -->
- <skip />
- <!-- no translation found for work_mode_off_message (7319580997683623309) -->
- <skip />
+ <string name="work_mode_off_title" msgid="961171256005852058">"অফিস অ্যাপ চালু করবেন?"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"আপনার অফিস অ্যাপ এবং বিজ্ঞপ্তিতে অ্যাক্সেস পান"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2f9b6c0..0ae3e7a 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -656,7 +656,7 @@
<string name="face_error_lockout" msgid="7864408714994529437">"Příliš mnoho pokusů. Zkuste to později."</string>
<string name="face_error_lockout_permanent" msgid="8277853602168960343">"Příliš mnoho pokusů. Odemknutí obličejem bylo deaktivováno."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Obličej se nepodařilo ověřit. Zkuste to znovu."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ověření obličejem nemáte nastavené."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"Odemknutí obličejem nemáte nastavené."</string>
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Odemknutí obličejem na tomto zařízení není podporováno."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasně deaktivován."</string>
<string name="face_name_template" msgid="3877037340223318119">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 2246e95..953fa17 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage face unlock hardware"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use face unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use face unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up face unlock"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try face unlock again."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock cancelled by user."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face unlock disabled."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Try again"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Unlock for all features and data"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum face unlock attempts exceeded"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum Face Unlock attempts exceeded"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"No SIM card"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"No SIM card in tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"No SIM card in your Android TV device."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 33c6d71..b3b1ff5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage face unlock hardware"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use face unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use face unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up face unlock"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try face unlock again."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock cancelled by user."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face unlock disabled."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Try again"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Unlock for all features and data"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum face unlock attempts exceeded"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum Face Unlock attempts exceeded"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"No SIM card"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"No SIM card in tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"No SIM card in your Android TV device."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a08ad1d..0c60a02 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage face unlock hardware"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use face unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use face unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up face unlock"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try face unlock again."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock cancelled by user."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face unlock disabled."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Try again"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Unlock for all features and data"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum face unlock attempts exceeded"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum Face Unlock attempts exceeded"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"No SIM card"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"No SIM card in tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"No SIM card in your Android TV device."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 44eba89..3830047 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage face unlock hardware"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use face unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use face unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up face unlock"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try face unlock again."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock cancelled by user."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face unlock disabled."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Try again"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Unlock for all features and data"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum face unlock attempts exceeded"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Maximum Face Unlock attempts exceeded"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"No SIM card"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"No SIM card in tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"No SIM card in your Android TV device."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 27b8f69..8b1e889 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1271,12 +1271,12 @@
<string name="new_app_action" msgid="547772182913269801">"Abrir <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
<string name="new_app_description" msgid="1958903080400806644">"<xliff:g id="OLD_APP">%1$s</xliff:g> se cerrará sin guardar"</string>
<string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> ha superado el límite de memoria"</string>
- <string name="dump_heap_ready_notification" msgid="2302452262927390268">"El volcado de pila <xliff:g id="PROC">%1$s</xliff:g> está listo"</string>
- <string name="dump_heap_notification_detail" msgid="8431586843001054050">"Se ha recopilado un volcado de pila. Toca para compartir."</string>
- <string name="dump_heap_title" msgid="4367128917229233901">"¿Compartir volcado de pila?"</string>
- <string name="dump_heap_text" msgid="1692649033835719336">"El proceso <xliff:g id="PROC">%1$s</xliff:g> ha superado su límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Hay un volcado de pila disponible que puedes compartir con su desarrollador (ten cuidado, ya que puede incluir información personal a la que tenga acceso la aplicación)."</string>
- <string name="dump_heap_system_text" msgid="6805155514925350849">"El proceso <xliff:g id="PROC">%1$s</xliff:g> ha superado su límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Hay un volcado de pila disponible que puedes compartir. Ten cuidado, ya que puede incluir información personal sensible a la que el proceso puede acceder, como texto que hayas introducido."</string>
- <string name="dump_heap_ready_text" msgid="5849618132123045516">"Hay un volcado de pila del proceso <xliff:g id="PROC">%1$s</xliff:g> que puedes compartir. Ten cuidado, ya que puede incluir información personal sensible a la que el proceso puede acceder, como texto que hayas introducido."</string>
+ <string name="dump_heap_ready_notification" msgid="2302452262927390268">"El volcado de montículo <xliff:g id="PROC">%1$s</xliff:g> está listo"</string>
+ <string name="dump_heap_notification_detail" msgid="8431586843001054050">"Se ha recopilado un volcado de montículo. Toca para compartir."</string>
+ <string name="dump_heap_title" msgid="4367128917229233901">"¿Compartir volcado de montículo?"</string>
+ <string name="dump_heap_text" msgid="1692649033835719336">"El proceso <xliff:g id="PROC">%1$s</xliff:g> ha superado su límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Hay un volcado de montículo disponible que puedes compartir con su desarrollador (ten cuidado, ya que puede incluir información personal a la que tenga acceso la aplicación)."</string>
+ <string name="dump_heap_system_text" msgid="6805155514925350849">"El proceso <xliff:g id="PROC">%1$s</xliff:g> ha superado su límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Hay un volcado de montículo disponible que puedes compartir. Ten cuidado, ya que puede incluir información personal sensible a la que el proceso puede acceder, como texto que hayas introducido."</string>
+ <string name="dump_heap_ready_text" msgid="5849618132123045516">"Hay un volcado de montículo del proceso <xliff:g id="PROC">%1$s</xliff:g> que puedes compartir. Ten cuidado, ya que puede incluir información personal sensible a la que el proceso puede acceder, como texto que hayas introducido."</string>
<string name="sendText" msgid="493003724401350724">"Selecciona una acción para el texto"</string>
<string name="volume_ringtone" msgid="134784084629229029">"Volumen del timbre"</string>
<string name="volume_music" msgid="7727274216734955095">"Volumen de multimedia"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 42e084c..a74b62a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"مدیریت سختافزار «بازگشایی با چهره»"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"مدیریت سختافزار «قفلگشایی با چهره»"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"به برنامه امکان میدهد روشهایی را برای افزودن و حذف الگوهای چهره جهت استفاده فرابخواند."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"استفاده از سختافزار «بازگشایی با چهره»"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"به برنامه امکان میدهد از سختافزار «بازگشایی با چهره» برای اصالتسنجی استفاده کند"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"بازگشایی با چهره"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"استفاده از سختافزار «قفلگشایی با چهره»"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"به برنامه امکان میدهد از سختافزار «قفلگشایی با چهره» برای اصالتسنجی استفاده کند"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"قفلگشایی با چهره"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ثبت مجدد چهره"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"برای بهبود تشخیص، لطفاً چهرهتان را دوباره ثبت کنید"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"راهاندازی «بازگشایی با چهره»"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"راهاندازی «قفلگشایی با چهره»"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"برای باز کردن قفل تلفن خود به آن نگاه کنید"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"راهاندازی روشهای بیشتر برای باز کردن قفل"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"برای افزودن اثر انگشت، ضربه بزنید"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چهره تأیید نشد. سختافزار در دسترس نیست."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"«بازگشایی با چهره» را دوباره امتحان کنید."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"«قفلگشایی با چهره» را دوباره امتحان کنید."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"داده چهره جدید ذخیره نشد. اول داده چهره قدیمی را حذف کنید."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"عملیات شناسایی چهره لغو شد."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"کاربر «بازگشایی با چهره» را لغو کرد."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"کاربر «قفلگشایی با چهره» را لغو کرد."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"تعداد تلاشها بیشازحد مجاز است. «بازگشایی با چهره» غیرفعال است."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"تعداد تلاشها بیشازحد مجاز است. «قفلگشایی با چهره» غیرفعال است."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"چهره تأیید نشد. دوباره امتحان کنید."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"«بازگشایی با چهره» را راهاندازی نکردهاید."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"«بازگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"«قفلگشایی با چهره» را راهاندازی نکردهاید."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"«قفلگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"حسگر بهطور موقت غیرفعال است."</string>
<string name="face_name_template" msgid="3877037340223318119">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"استفاده از «بازگشایی با چهره»"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"استفاده از «قفلگشایی با چهره»"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"استفاده از قفل صفحه یا چهره"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"برای ادامه، از چهرهتان استفاده کنید"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"برای ادامه، از تشخیص چهره یا قفل صفحه استفاده کنید"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوباره امتحان کنید"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"دوباره امتحان کنید"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"باز کردن قفل تمام قابلیتها و دادهها"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"دفعات تلاش برای «بازگشایی با چهره» از حداکثر مجاز بیشتر شد"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"دفعات تلاش برای «قفلگشایی با چهره» از حداکثر مجاز بیشتر شد"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"سیم کارت موجود نیست"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"سیم کارت درون رایانهٔ لوحی نیست."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"هیچ سیمکارتی در دستگاه Android TV شما قرار داده نشده است."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"گسترده کردن منطقه بازگشایی شده."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"باز کردن قفل با کشیدن انگشت روی صفحه."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"باز کردن قفل با الگو."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"بازگشایی با چهره."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"قفلگشایی با چهره."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"باز کردن قفل با پین."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"قفل پین سیمکارت باز شد."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"قفل Puk سیمکارت باز شد."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 22a1bcd..bd2362b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -611,9 +611,9 @@
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"gérer les composants de Face Unlock"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Autorise l\'appli à invoquer des méthodes pour ajouter et supprimer des modèles de visages."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utiliser les composants de Face Unlock"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autorise l\'application à utiliser les composants de Face Unlock pour l\'authentification"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utiliser le matériel de déverrouillage par authentification faciale"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autorise l\'appli à utiliser le matériel de déverrouillage par authentification faciale"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Déverrouillage par authentification faciale"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Enregistrer à nouveau votre visage"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Pour améliorer la reconnaissance, veuillez enregistrer à nouveau votre visage"</string>
<string name="face_setup_notification_title" msgid="550617822603450009">"Configurer Face Unlock"</string>
@@ -643,7 +643,7 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. valider visage. Matériel non disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Réessayez d\'activer Face Unlock."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Réessayez d\'activer le déverrouillage."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Impossible stocker nouv. visages. Veuillez en supprimer un."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Opération de reconnaissance faciale annulée."</string>
<string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock annulé par l\'utilisateur."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index e837891..6bf1ff8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1022,8 +1022,7 @@
<string name="text_copied" msgid="2531420577879738860">"ક્લિપબોર્ડ પર ટેક્સ્ટ કૉપિ કરી."</string>
<string name="copied" msgid="4675902854553014676">"કૉપિ કરેલ"</string>
<string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>માંથી કૉપિ કરાયેલો ડેટા <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>માં પેસ્ટ કરવામાં આવ્યો"</string>
- <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
- <skip />
+ <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> દ્વારા તમારા ક્લિપબોર્ડ પરથી પેસ્ટ કરવામાં આવ્યું"</string>
<string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> દ્વારા તમે કૉપિ કરેલી ટેક્સ્ટ પેસ્ટ કરાઈ"</string>
<string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> દ્વારા તમે કૉપિ કરેલી છબી પેસ્ટ કરાઈ"</string>
<string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> દ્વારા તમે કૉપિ કરેલું કન્ટેન્ટ પેસ્ટ કરાયું"</string>
@@ -1260,14 +1259,10 @@
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> તૈયાર કરી રહ્યું છે."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"ઍપ્લિકેશનો શરૂ કરી રહ્યાં છે."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"બૂટ સમાપ્ત કરી રહ્યાં છે."</string>
- <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
- <skip />
+ <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"સ્ક્રીન બંધ કરીએ?"</string>
+ <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"તમારી ફિંગરપ્રિન્ટની સેટિંગનું સેટઅપ કરતી વખતે, તમે પાવર બટન દબાવ્યું.\n\nઆનાથી સામાન્ય રીતે તમારી સ્ક્રીન બંધ થઈ જાય છે."</string>
+ <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"બંધ કરો"</string>
+ <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"રદ કરો"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> ચાલુ છે"</string>
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"ગેમ પર પાછા આવવા માટે ટૅપ કરો"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ગેમ પસંદ કરો"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 15bf3e9..894c099 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1869,8 +1869,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, կապի ծառայություններ և այլ գործառույթներ։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
- <string name="battery_saver_description" msgid="8518809702138617167">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, կապի ծառայություններ և այլ գործառույթներ։"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 0426a81..01d4219 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -609,11 +609,11 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"жүзүнөн таануу функциясынын аппараттык камсыздоосун башкаруу"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"жүзүнөн таанып ачуу функциясынын аппараттык камсыздоосун башкаруу"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Колдонмого пайдалануу үчүн жүздүн үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"аппараттык камсыздоо үчүн жүзүнөн таанууну колдонуу"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Колдонмо аныктыкты текшерүүдө Жүзүнөн таануу функциясынын аппараттык камсыздоосун колдонот"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Жүзүнөн таануу"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"аппараттык камсыздоо үчүн жүзүнөн таанып ачуу функциясын колдонуу"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Колдонмо аныктыкты текшерүүдө Жүзүнөн таанып ачуу функциясынын аппараттык камсыздоосун колдонот"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Жүзүнөн таанып ачуу"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Жүзүңүздү кайра таанытыңыз."</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Мыкты таануу үчүн, жүзүңүздү кайра таанытыңыз"</string>
<string name="face_setup_notification_title" msgid="550617822603450009">"Жүзүнөн таанып ачуу функциясын жөндөңүз"</string>
@@ -643,15 +643,15 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Жүз ырасталбай жатат. Аппараттык камсыздоо жеткиликсиз."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Жүзүнөн таануу функциясын кайра текшерип көрүңүз."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Жүзүнөн таанып ачуу функциясын кайра текшерип көрүңүз."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Жаңы жүздү сактоо мүмкүн эмес. Адегенде эскисин өчүрүңүз."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Жүзүнөн таануу функциясын колдонуучу өчүрүп салды."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Жүзүнөн таанып ачуу функциясын колдонуучу өчүрүп салды."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Өтө көп жолу аракет жасадыңыз. Бир аздан кийин кайталап көрүңүз."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Өтө көп жолу аракет кылдыңыз. Жүзүнөн таануу функциясы өчүрүлдү."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Өтө көп жолу аракет кылдыңыз. Жүзүнөн таанып ачуу функциясы өчүрүлдү."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Жүз ырасталбай жатат. Кайталап көрүңүз."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Жүзүнөн таануу функциясын жөндөй элексиз."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таануу функциясы бул түзмөктө иштебейт."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"Жүзүнөн таанып ачуу функциясын жөндөй элексиз."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таанып ачуу функциясы бул түзмөктө иштебейт."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сенсор убактылуу өчүрүлгөн."</string>
<string name="face_name_template" msgid="3877037340223318119">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string>
<string name="face_app_setting_name" msgid="8130135875458467243">"Жүзүнөн таанып ачууну колдонуу"</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Бөгөттөн чыгаруу аймагын кеңейтүү."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Жылмыштырып ачуу."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Үлгү менен ачуу."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Жүзүнөн таануу"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Жүзүнөн таанып ачуу"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Пин код менен ачуу."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-картанын кулпусун PIN-код менен ачуу."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-картанын кулпусун PUK-код менен ачуу."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 838c49a..6053a1c 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"царайгаар тайлах техник хангамжийг удирдах"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"царайгаар түгжээ тайлах техник хангамжийг удирдах"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Аппад царайны загварыг ашиглахын тулд нэмэх эсвэл устгах аргыг идэвхжүүлэхийг зөвшөөрдөг."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"царайгаар тайлах техник хангамж ашиглах"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Аппад царайгаар тайлах техник хангамжийг баталгаажуулалтад ашиглахыг зөвшөөрдөг"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Царайгаар тайлах"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"царайгаар түгжээ тайлах техник хангамж ашиглах"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Аппад царайгаар түгжээ тайлах техник хангамжийг баталгаажуулалтад ашиглахыг зөвшөөрдөг"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Царайгаар түгжээ тайлах"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Царайгаа дахин бүртгүүлнэ үү"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Танилтыг сайжруулахын тулд царайгаа дахин бүртгүүлнэ үү"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Царайгаар тайлах онцлогийг тохируулна уу"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"Царайгаар түгжээ тайлах онцлогийг тохируулна уу"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Утас руугаа харж түгжээг нь тайлна уу"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Түгжээ тайлах илүү олон арга тохируулна уу"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Хурууны хээ нэмэхийн тулд товшино уу"</string>
@@ -643,19 +643,19 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Царайг бататгаж чадсангүй. Техник хангамж боломжгүй байна."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Царайгаар тайлахыг дахин оролдоно уу."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Царайгаар түгжээ тайлахыг дахин оролдоно уу."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Царайн шинэ өгөгдлийг хадгалж чадсангүй. Эхлээд хуучин өгөгдлийг устгана уу."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Царайны үйл ажиллагааг цуцаллаа."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Хэрэглэгч царайгаар тайлахыг цуцалсан."</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"Хэрэглэгч царайгаар түгжээ тайлахыг цуцалсан."</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Хэтэрхий олон удаа оролдлоо. Царайгаар тайлахыг идэвхгүй болголоо."</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Хэтэрхий олон удаа оролдлоо. Царайгаар түгжээ тайлахыг идэвхгүй болголоо."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Царайг бататгаж чадсангүй. Дахин оролдоно уу."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Та царайгаар тайлахыг тохируулаагүй байна."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"Та царайгаар түгжээ тайлахыг тохируулаагүй байна."</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар түгжээ тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
<string name="face_name_template" msgid="3877037340223318119">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Царайгаар тайлахыг ашиглах"</string>
- <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Царай эсвэл дэлгэцийн түгжээ ашиглах"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Царайгаар түгжээ тайлахыг ашиглах"</string>
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Царайгаар түгжээ тайлах эсвэл дэлгэцийн түгжээ ашиглах"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Үргэлжлүүлэхийн тулд царайгаа ашиглана уу"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Үргэлжлүүлэхийн тулд царай эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
<string-array name="face_error_vendor">
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дахин оролдох"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Дахин оролдох"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Бүх онцлог, өгөгдлийн түгжээг тайлах"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Нүүрээр түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Царайгаар түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"SIM карт байхгүй"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Таблет SIM картгүй."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Таны Android TV төхөөрөмжид SIM карт алга."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Түгжээгүй хэсгийг өргөсгөх."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Тайлах гулсуулалт."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Тайлах хээ."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Царайгаар тайлах"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Царайгаар түгжээ тайлах"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Тайлах пин."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim-н пин кодыг тайлна уу."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim-н Puk кодыг тайлна уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index ad954c8..aae0c5b 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1869,10 +1869,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
- <skip />
- <!-- no translation found for battery_saver_description (8518809702138617167) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string>
@@ -1975,10 +1973,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"अॅप उघडा"</string>
- <!-- no translation found for work_mode_off_title (961171256005852058) -->
- <skip />
- <!-- no translation found for work_mode_off_message (7319580997683623309) -->
- <skip />
+ <string name="work_mode_off_title" msgid="961171256005852058">"कार्य अॅप्स सुरू करायची का?"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"तुमची कार्य ॲप्स आणि सूचना यांचा अॅक्सेस मिळवा"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"सुरू करा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index f775455..9ecede5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"မျက်နှာမှတ် သော့ဖွင့်ခြင်း စက်ပစ္စည်းကို စီမံခြင်း"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"မျက်နှာပြလော့ခ်ဖွင့်သည့် စက်ပစ္စည်းကို စီမံခြင်း"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"အသုံးပြုရန်အတွက် မျက်နှာပုံစံထည့်ရန် (သို့) ဖျက်ရန်နည်းလမ်းကို အက်ပ်အား သုံးခွင့်ပြုသည်။"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"မျက်နှာမှတ် သော့ဖွင့်ခြင်း စက်ပစ္စည်းကို သုံးပါ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"အထောက်အထားစိစစ်ရန်အတွက် ဤအက်ပ်အား မျက်နှာမှတ်သော့ဖွင့်ခြင်း စက်ပစ္စည်းကိုသုံးခွင့်ပြုသည်"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"မျက်နှာမှတ် သော့ဖွင့်ခြင်း"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"မျက်နှာပြ လော့ခ်ဖွင့်သည့် စက်ပစ္စည်းကို သုံးပါ"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"အထောက်အထားစိစစ်ရန်အတွက် ဤအက်ပ်အား မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း စက်ပစ္စည်းကိုသုံးခွင့်ပြုသည်"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"သင့်မျက်နှာကို စာရင်းပြန်သွင်းပါ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ပိုမှတ်မိစေရန် သင့်မျက်နှာကို စာရင်းပြန်သွင်းပါ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို စနစ်ထည့်သွင်းပါ"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း စနစ်ထည့်သွင်းပါ"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"သင့်ဖုန်းကိုကြည့်၍ သော့ဖွင့်ပါ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"သော့ဖွင့်ရန် နောက်ထပ်နည်းလမ်းများကို စနစ်ထည့်သွင်းပါ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"လက်ဗွေထည့်ရန် တို့ပါ"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"မျက်နှာဒေတာအသစ် သိမ်း၍မရပါ။ အဟောင်းကို အရင်ဖျက်ပါ။"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"မှတ်နှာမှတ် သော့ဖွင့်ခြင်းကို အသုံးပြုသူက မလုပ်တော့ပါ။"</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"မှတ်နှာပြ လော့ခ်ဖွင့်ခြင်းကို မလုပ်တော့ပါ။"</string>
<string name="face_error_lockout" msgid="7864408714994529437">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"စမ်းသပ်ကြိမ် များနေပြီ။ မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို ပိတ်လိုက်ပါပြီ။"</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"စမ်းသပ်ကြိမ် များနေပြီ။ မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း ပိတ်လိုက်ပါပြီ။"</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို ထည့်သွင်းမထားပါ"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း ထည့်သွင်းမထားပါ"</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
<string name="face_name_template" msgid="3877037340223318119">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"မျက်နှာမှတ်သော့ဖွင့်ခြင်းကို သုံးခြင်း"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"မျက်နှာပြ လော့ခ်ဖွင့်ရန်"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"မျက်နှာမှတ်သော့ဖွင့်ခြင်း (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ရှေ့ဆက်ရန် သင့်မျက်နှာကို သုံးပါ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ရှေ့ဆက်ရန် သင်၏ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ထပ် စမ်းပါ"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"ထပ် စမ်းပါ"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"ဝန်ဆောင်မှုနှင့် ဒေတာအားလုံးအတွက် လော့ခ်ဖွင့်ပါ"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"မျက်မှာမှတ် သော့ဖွင့်ခြင်း ခွင့်ပြုသော အကြိမ်ရေထက် ကျော်လွန်သွားပါပြီ"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"မျက်မှာပြ လော့ခ်ဖွင့်ခြင်း ခွင့်ပြုသော အကြိမ်ရေထက် ကျော်လွန်သွားပါပြီ"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ဆင်းကဒ် မရှိပါ"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"တက်ပလက်ထဲတွင်း ဆင်းကဒ် မရှိပါ"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"သင့် Android TV စက်ပစ္စည်းပေါ်တွင် ဆင်းမ်ကတ်မရှိပါ။"</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"သော့မချထားသာ နယ်ပယ်ကို ချဲ့ပါ"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ဘေးတိုက်ပွတ်ဆွဲ၍ သော့ဖွင့်ခြင်း"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ပုံစံဖြင့် သော့ဖွင့်ခြင်း"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"မျက်နှာမှတ် သော့ဖွင့်ခြင်း"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ပင်နံပါတ်ဖြင့် သော့ဖွင့်ခြင်း"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ဆင်းမ်ကဒ် ပင်နံပါတ်လော့ခ်ဖွင့်ပါ။"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ဆင်းမ်ကဒ် Puk လော့ခ်ဖွင့်ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4e55f78..25db688 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -611,7 +611,7 @@
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"administrere maskinvare for Ansiktslås"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Lar appen bruke metoder for å legge til og slette ansiktmaler for bruk."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"bruke maskinvare for Ansiktslås"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"bruk maskinvare for Ansiktslås"</string>
<string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Lar appen bruke maskinvare for Ansiktslås til autentisering"</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ansiktslås"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registrer ansiktet ditt på nytt"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 53a8273..a0fd8cb 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1022,8 +1022,7 @@
<string name="text_copied" msgid="2531420577879738860">"क्लिपबोर्डमा प्रतिलिप गरिएको पाठ।"</string>
<string name="copied" msgid="4675902854553014676">"प्रतिलिपि गरियो"</string>
<string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> मा रहेको डेटा कपी गरी <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> मा पेस्ट गरियो"</string>
- <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
- <skip />
+ <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ले तपाईंको क्लिपबोर्डमा रहेको जानकारी पेस्ट गरेको छ"</string>
<string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ले तपाईंले कपी गरेको टेक्स्ट पेस्ट गरेको छ"</string>
<string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ले तपाईंले कपी गरेको एउटा फोटो पेस्ट गरेको छ"</string>
<string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ले तपाईंले कपी गरेको सामग्री पेस्ट गरेको छ"</string>
@@ -1260,14 +1259,10 @@
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> तयारी गर्दै।"</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"सुरुवात एपहरू।"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"बुट पुरा हुँदै।"</string>
- <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
- <skip />
- <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
- <skip />
+ <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"स्क्रिन अफ गर्ने हो?"</string>
+ <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"आफ्नो फिंगरप्रिन्ट सेटअप गर्दा तपाईंले पावर बटन थिच्नुभयो।\n\nयसो गर्दा सामान्यतया तपाईंको स्क्रिन अफ हुन्छ।"</string>
+ <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"अफ गर्नुहोस्"</string>
+ <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"रद्द गर्नुहोस्"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string>
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"खेलमा फर्कन ट्याप गर्नुहोस्"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"खेल छनौट गर्नुहोस्"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bc0342a..8f24a7c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Tente novamente"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbloqueio para todos os recursos e dados"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"O número máximo de tentativas de desbloqueio por reconhecimento facial foi excedido"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Sem chip"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Não há um chip no tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Nenhum chip no seu dispositivo Android TV."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bc0342a..8f24a7c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Tente novamente"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbloqueio para todos os recursos e dados"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"O número máximo de tentativas de desbloqueio por reconhecimento facial foi excedido"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Sem chip"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Não há um chip no tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Nenhum chip no seu dispositivo Android TV."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c338e88..9fe0f7e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -618,7 +618,7 @@
<string name="permlab_manageFace" msgid="4569549381889283282">"Управление аппаратным обеспечением для функции \"Фейсконтроль\""</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Приложение сможет добавлять и удалять шаблоны лиц."</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"Использование аппаратного обеспечения для функции \"Фейсконтроль\""</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Приложение сможет использовать для аутентификации аппаратное обеспечение Фейсконтроля."</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Приложение сможет использовать для аутентификации аппаратное обеспечение фейсконтроля."</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Фейсконтроль"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Зарегистрируйте лицо ещё раз"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Чтобы улучшить распознавание лица, зарегистрируйте его ещё раз"</string>
@@ -649,7 +649,7 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Не удалось распознать лицо. Сканер недоступен."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Попробуйте воспользоваться функцией ещё раз."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Попробуйте воспользоваться фейсконтролем ещё раз."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Недостаточно места. Удалите старые данные для распознавания."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Распознавание отменено"</string>
<string name="face_error_user_canceled" msgid="8553045452825849843">"Фейсконтроль: операция отменена пользователем."</string>
@@ -893,7 +893,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторите попытку"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Повторите попытку"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Разблок. для доступа ко всем функциям и данным"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Все попытки войти с помощью Фейсконтроля использованы"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Все попытки войти с помощью фейсконтроля использованы"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Нет SIM-карты"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"SIM-карта не установлена."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"В устройстве Android TV нет SIM-карты."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 49ec75c..911dbc1 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -609,10 +609,10 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"menaxho harduerin për shkyçjen me fytyrën"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"menaxho harduerin për shkyçjen me fytyrë"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Lejon aplikacionin të aktivizojë mënyra për shtim e fshirje të shablloneve të përdorura."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"përdor harduerin e shkyçjes me fytyrën"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Lejon aplikacionin të përdorë harduerin e shkyçjes me fytyrën për procesin e vërtetimit"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"përdor harduerin e shkyçjes me fytyrë"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Lejon aplikacionin të përdorë harduerin e shkyçjes me fytyrë për procesin e vërtetimit"</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Shkyçja me fytyrë"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Regjistro përsëri fytyrën tënde"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Për të përmirësuar njohjen, regjistro përsëri fytyrën tënde"</string>
@@ -643,7 +643,7 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Fytyra s\'mund të verifikohet. Hardueri nuk ofrohet."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Provo përsëri shkyçjen me fytyrën."</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"Provo përsëri shkyçjen me fytyrë."</string>
<string name="face_error_no_space" msgid="5649264057026021723">"S\'mund të ruhen të dhëna të reja fytyre. Fshi një të vjetër në fillim."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Veprimi me fytyrën u anulua."</string>
<string name="face_error_user_canceled" msgid="8553045452825849843">"Shkyçja me fytyrë u anulua nga përdoruesi."</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Provo sërish"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Provo sërish"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Shkyçe për të gjitha funksionet dhe të dhënat"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Tentativat maksimale të \"Shkyçjes me fytyrë\" u tejkaluan"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Përpjektet maksimale të \"Shkyçjes me fytyrë\" u tejkaluan"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Nuk ka kartë SIM"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Nuk ka kartë SIM në tablet."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Nuk ka kartë SIM në pajisjen tënde Android TV."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zgjero zonën e shkyçjes."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Rrëshqit shkyçjen."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Shkyçje me motiv."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Shkyçje me fytyrë."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Shkyçja me fytyrë."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Shkyçje me PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Shkyçja e kartës SIM me kodin PIN"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Shkyçja e kartës SIM me kodin PUK"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 11441b3..d90e271 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -609,14 +609,14 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"چہرے کے ذریعے غیر مقفل کرنے والے ہارڈ ویئر کا نظم کریں"</string>
+ <string name="permlab_manageFace" msgid="4569549381889283282">"فیس اَنلاک والے ہارڈ ویئر کا نظم کریں"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"ایپ کو چہرے کی تمثیلات شامل اور حذف کرنے کے طریقوں کو کالعدم قرار دینے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"چہرے کے ذریعے غیر مقفل کرنے والا ہارڈ ویئر استعمال کریں"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ایپ کو تصدیق کے لیے چہرے کے ذریعے غیر مقفل کرنے کا ہارڈ ویئر استعمال کرنے کی اجازت دیتی ہے"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"چہرے کے ذریعے غیر مقفل کریں"</string>
+ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"فیس اَنلاک والا ہارڈ ویئر استعمال کریں"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ایپ کو تصدیق کے لیے فیس اَنلاک کا ہارڈ ویئر استعمال کرنے کی اجازت دیتی ہے"</string>
+ <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"فیس اَنلاک"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"اپنے چہرے کو دوبارہ مندرج کریں"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"شناخت کو بہتر بنانے کے لیے براہ کرم اپنے چہرے کو دوبارہ مندرج کریں"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"چہرے کے ذریعے غیر مقفل کرنا سیٹ اپ کریں"</string>
+ <string name="face_setup_notification_title" msgid="550617822603450009">"فیس اَنلاک سیٹ اپ کریں"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"اپنے فون کی طرف دیکھ کر اسے غیر مقفل کریں"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"غیر مقفل کرنے کے مزید طریقے سیٹ اپ کریں"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"فنگر پرنٹ شامل کرنے کیلئے تھپتھپائیں"</string>
@@ -643,18 +643,18 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چہرے کی توثیق نہیں کی جا سکی۔ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"چہرے کے ذریعے غیر مقفل کرنے کو دوبارہ آزمائیں۔"</string>
+ <string name="face_error_timeout" msgid="522924647742024699">"فیس اَنلاک کو دوبارہ آزمائیں۔"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"چہرے کا نیا ڈیٹا اسٹور نہیں کر سکتے۔ پہلے پرانا حذف کریں۔"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"چہرے پر ہونے والی کارروائی منسوخ ہو گئی۔"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"صارف نے چہرے کے ذریعے غیر مقفل کرنے کو منسوخ کر دیا۔"</string>
+ <string name="face_error_user_canceled" msgid="8553045452825849843">"صارف نے فیس اَنلاک کو منسوخ کر دیا۔"</string>
<string name="face_error_lockout" msgid="7864408714994529437">"کافی زیادہ کوششیں کی گئیں۔ دوبارہ کوشش کریں۔"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"کافی زیادہ کوششیں۔ چہرے کے ذریعے غیر مقفل کرنا غیر فعال کر دیا گیا۔"</string>
+ <string name="face_error_lockout_permanent" msgid="8277853602168960343">"کافی زیادہ کوششیں۔ فیس اَنلاک غیر فعال کر دیا گیا۔"</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"چہرے کی توثیق نہیں کی جا سکی۔ پھر آزمائيں۔"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"آپ نے بذریعہ چہرہ غیر مقفل کرنے کو سیٹ نہیں کیا ہے۔"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر چہرے کے ذریعے غیر مقفل کرنا تعاون یافتہ نہیں ہے۔"</string>
+ <string name="face_error_not_enrolled" msgid="7369928733504691611">"آپ نے فیس اَنلاک کو سیٹ نہیں کیا ہے۔"</string>
+ <string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر فیس اَنلاک تعاون یافتہ نہیں ہے۔"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"سینسر عارضی طور غیر فعال ہے۔"</string>
<string name="face_name_template" msgid="3877037340223318119">"چہرہ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"چہرے کے ذریعے غیر مقفل کرنا استعمال کریں"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"فیس اَنلاک استعمال کریں"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"چہرہ یا اسکرین لاک استعمال کریں"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"جاری رکھنے کے لیے اپنے چہرے کا استعمال کریں"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"جاری رکھنے کے لیے اپنے چہرے یا اسکرین لاک کا استعمال کریں"</string>
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوبارہ کوشش کریں"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"دوبارہ کوشش کریں"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"تمام خصوصیات اور ڈیٹا کیلئے غیر مقفل کریں"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"چہرہ کے ذریعے غیر مقفل کریں کی زیادہ سے زیادہ کوششوں سے تجاوز کرگیا"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"فیس اَنلاک کی زیادہ سے زیادہ کوششوں سے تجاوز کرگیا"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"کوئی SIM کارڈ نہیں ہے"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"آپ کے Android TV آلہ میں SIM کارڈ نہیں ہے۔"</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"غیر مقفل کرنے والے علاقے کو پھیلائیں۔"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"سلائیڈ کے ذریعے غیر مقفل کریں۔"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"پیٹرن کے ذریعے غیر مقفل کریں۔"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"چہرے کے ذریعے غیر مقفل کریں۔"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"فیس اَنلاک۔"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"پن کے ذریعے غیر مقفل کریں۔"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim پن غیر مقفل۔"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk غیر مقفل۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 8320aaf..d536056 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -887,7 +887,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Qaytadan urining"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Qaytadan urining"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Barcha funksiya va ma’lumotlar uchun qulfdan chiqaring"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Yuzni tanitib qulfni ochishga urinish miqdoridan oshib ketdi"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Yuz bilan ochishga urinish miqdoridan oshib ketdi"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"SIM karta solinmagan"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Planshetingizda SIM karta yo‘q."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Android TV qurilmangizda SIM karta topilmadi."</string>
@@ -957,7 +957,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Qulfni ochish maydonini kengaytirish."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Qulfni silab ochish"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Grafik kalit bilan ochish."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Qulfni yuzni tanitib ochish"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Yuz bilan ochish."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin qulfini ochish."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM kartani PIN kod bilan ochish."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM kartani PUK kod bilan ochish."</string>
@@ -1869,8 +1869,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi va fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi.\n\n"<annotation id="url">"Batafsil"</annotation></string>
- <string name="battery_saver_description" msgid="8518809702138617167">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi va fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi.\n\n"<annotation id="url">"Batafsil"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Yoqish"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4fb57cf..44bbb2e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1260,7 +1260,7 @@
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"正在啟動應用程式。"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"啟動完成。"</string>
<string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"要關閉螢幕嗎?"</string>
- <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"設定指紋時需要按下開關按鈕。\n\n此操作通常會關閉螢幕。"</string>
+ <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"您在設定指紋時按了開關按鈕。\n\n螢幕通常會因此而關閉。"</string>
<string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"關閉"</string>
<string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"取消"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"正在執行 <xliff:g id="APP">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6386274..ef0dc37 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2593,6 +2593,12 @@
<!-- The code for this component is located in the given split.
<p>NOTE: This is only applicable to instant app. -->
<attr name="splitName" />
+ <!-- Set of attribution tags that should be automatically applied to this component.
+ <p>
+ Each instance of this ContentProvider will be automatically configured with
+ Context.createAttributionContext() using the first attribution tag
+ contained here. -->
+ <attr name="attributionTags" />
</declare-styleable>
<!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -2728,6 +2734,12 @@
<attr name="useAppZygote" format="boolean" />
<!-- If this is a foreground service, specify its category. -->
<attr name="foregroundServiceType" />
+ <!-- Set of attribution tags that should be automatically applied to this component.
+ <p>
+ Each instance of this Service will be automatically configured with
+ Context.createAttributionContext() using the first attribution tag
+ contained here. -->
+ <attr name="attributionTags" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
@@ -2765,6 +2777,12 @@
<attr name="exported" />
<attr name="singleUser" />
<attr name="directBootAware" />
+ <!-- Set of attribution tags that should be automatically applied to this component.
+ <p>
+ Each instance of this BroadcastReceiver will be automatically configured with
+ Context.createAttributionContext() using the first attribution tag
+ contained here. -->
+ <attr name="attributionTags" />
</declare-styleable>
<!-- The <code>activity</code> tag declares an
@@ -2892,10 +2910,12 @@
<p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} -->
<attr name="preferMinimalPostProcessing" format="boolean"/>
- <!-- Specify the attributionTags to be used if a permission is required due to
- {@link android.content.Context#sendBroadcast(Intent, String)} being used.
- Multiple tags can be specified separated by '|'. -->
- <attr name="attributionTags"/>
+ <!-- Set of attribution tags that should be automatically applied to this component.
+ <p>
+ Each instance of this Activity will be automatically configured with
+ Context.createAttributionContext() using the first attribution tag
+ contained here. -->
+ <attr name="attributionTags" />
<!-- Specifies whether a home sound effect should be played if the home app moves to
front after an activity with this flag set to <code>true</code>.
<p>The default value of this attribute is <code>true</code>.
@@ -2942,6 +2962,7 @@
<attr name="enabled" />
<attr name="exported" />
<attr name="parentActivityName" />
+ <attr name="attributionTags" />
</declare-styleable>
<!-- The <code>meta-data</code> tag is used to attach additional
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aa0d23b..eca623a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3936,6 +3936,9 @@
<!-- Handle volume keys directly in Window Manager without passing them to the foreground app -->
<bool name="config_handleVolumeKeysInWindowManager">false</bool>
+ <!-- Rely or not on hardcoded aliased streams table within AudioService -->
+ <bool name="config_handleVolumeAliasesUsingVolumeGroups">false</bool>
+
<!-- Volume level of in-call notification tone playback [0..1] -->
<item name="config_inCallNotificationVolume" format="float" type="dimen">.10</item>
@@ -4796,8 +4799,9 @@
<!-- Whether to select voice/data/sms preference without user confirmation -->
<bool name="config_voice_data_sms_auto_fallback">false</bool>
- <!-- Whether to enable the one-handed keyguard on the lock screen for wide-screen devices. -->
- <bool name="config_enableOneHandedKeyguard">false</bool>
+ <!-- Whether to enable dynamic keyguard positioning for wide screen devices (e.g. only using
+ half of the screen, to be accessible using only one hand). -->
+ <bool name="config_enableDynamicKeyguardPositioning">false</bool>
<!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot -->
<bool name="config_allow_pin_storage_for_unattended_reboot">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d440173..f2328567 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3632,6 +3632,7 @@
<java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
<java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
+ <java-symbol type="bool" name="config_handleVolumeAliasesUsingVolumeGroups" />
<java-symbol type="dimen" name="config_inCallNotificationVolume" />
<java-symbol type="string" name="config_inCallNotificationSound" />
<java-symbol type="integer" name="config_autoGroupAtCount" />
@@ -4259,7 +4260,7 @@
<java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
- <java-symbol type="bool" name="config_enableOneHandedKeyguard" />
+ <java-symbol type="bool" name="config_enableDynamicKeyguardPositioning" />
<java-symbol type="attr" name="colorAccentPrimary" />
<java-symbol type="attr" name="colorAccentSecondary" />
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 61f58b0..fd39cde 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -762,6 +762,62 @@
// }
// }
+ @Test
+ public void syncDisabling() throws Exception {
+ Properties properties1 = new Properties.Builder(NAMESPACE)
+ .setString(KEY, VALUE)
+ .build();
+ Properties properties2 = new Properties.Builder(NAMESPACE)
+ .setString(KEY, VALUE2)
+ .build();
+
+ try {
+ // Ensure the device starts in a known state.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+
+ // Assert starting state.
+ assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+ assertThat(DeviceConfig.setProperties(properties1)).isTrue();
+ assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
+ .isEqualTo(VALUE);
+
+ // Test disabled (persistent). Persistence is not actually tested, that would require
+ // a host test.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_PERSISTENT);
+ assertThat(DeviceConfig.isSyncDisabled()).isTrue();
+ assertThat(DeviceConfig.setProperties(properties2)).isFalse();
+ assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
+ .isEqualTo(VALUE);
+
+ // Return to not disabled.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+ assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+ assertThat(DeviceConfig.setProperties(properties2)).isTrue();
+ assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
+ .isEqualTo(VALUE2);
+
+ // Test disabled (persistent). Absence of persistence is not actually tested, that would
+ // require a host test.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT);
+ assertThat(DeviceConfig.isSyncDisabled()).isTrue();
+ assertThat(DeviceConfig.setProperties(properties1)).isFalse();
+ assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
+ .isEqualTo(VALUE2);
+
+ // Return to not disabled.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+ assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+ assertThat(DeviceConfig.setProperties(properties1)).isTrue();
+ assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
+ .isEqualTo(VALUE);
+ } finally {
+ // Try to return to the default sync disabled state in case of failure.
+ DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+
+ // NAMESPACE will be cleared by cleanUp()
+ }
+ }
+
private static boolean deleteViaContentProvider(String namespace, String key) {
ContentResolver resolver = InstrumentationRegistry.getContext().getContentResolver();
String compositeName = namespace + "/" + key;
diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
index 97e66c4..ee0b127 100644
--- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java
+++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
@@ -96,7 +96,8 @@
mCacheGenerationStore.set(0, ++mCurrentGeneration);
Bundle result = new Bundle();
- result.putBoolean(Settings.KEY_CONFIG_SET_RETURN, true);
+ result.putInt(Settings.KEY_CONFIG_SET_ALL_RETURN,
+ Settings.SET_ALL_RESULT_SUCCESS);
return result;
});
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
index 23fc35d..6457e3f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
@@ -35,11 +35,13 @@
private static final double PRECISION = 0.00001;
@Rule
- public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
- .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 1234.0); // Should be ignored
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
@Test
public void testDischargeTotals() {
+ // Nominal battery capacity should be ignored
+ mStatsRule.setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 1234.0);
+
final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
@@ -56,7 +58,7 @@
BatteryUsageStats batteryUsageStats = mStatsRule.apply(calculator);
assertThat(batteryUsageStats.getConsumedPower())
- .isWithin(PRECISION).of(380.0);
+ .isWithin(PRECISION).of(1200.0); // 3,600 - 2,400
assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(10);
assertThat(batteryUsageStats.getDischargedPowerRange().getLower())
.isWithin(PRECISION).of(360.0);
@@ -74,4 +76,34 @@
assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(100_000);
}
+
+ @Test
+ public void testDischargeTotals_chargeUahUnavailable() {
+ mStatsRule.setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0);
+
+ final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 90, 72, 3700, 0, 0, 0,
+ 1_000_000, 1_000_000, 1_000_000);
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 85, 72, 3700, 0, 0, 0,
+ 1_500_000, 1_500_000, 1_500_000);
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 80, 72, 3700, 0, 0, 0,
+ 2_000_000, 2_000_000, 2_000_000);
+
+ BatteryChargeCalculator calculator = new BatteryChargeCalculator();
+ BatteryUsageStats batteryUsageStats = mStatsRule.apply(calculator);
+
+ assertThat(batteryUsageStats.getConsumedPower())
+ .isWithin(PRECISION).of(380.0); // 9.5% of 4,000.
+ assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(10);
+ assertThat(batteryUsageStats.getDischargedPowerRange().getLower())
+ .isWithin(PRECISION).of(360.0); // 9% of 4,000
+ assertThat(batteryUsageStats.getDischargedPowerRange().getUpper())
+ .isWithin(PRECISION).of(400.0); // 10% of 4,000
+ assertThat(batteryUsageStats.getBatteryTimeRemainingMs()).isEqualTo(8_000_000);
+ assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(-1);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 623e77e..54d8701 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -363,7 +363,6 @@
assertEquals("Unexpected system cpu time for uid=" + testUids[i],
uidTimesUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
}
- verify(mCpuUidUserSysTimeReader).removeUid(isolatedUid);
// Add an isolated uid mapping and repeat the test.
@@ -453,7 +452,6 @@
}
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
mBatteryStatsImpl.getUidStats().get(invalidUid));
- verify(mCpuUidUserSysTimeReader).removeUid(invalidUid);
}
@Test
@@ -943,7 +941,6 @@
assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
}
- verify(mCpuUidFreqTimeReader).removeUid(isolatedUid);
// Add an isolated uid mapping and repeat the test.
@@ -1038,7 +1035,6 @@
}
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
mBatteryStatsImpl.getUidStats().get(invalidUid));
- verify(mCpuUidFreqTimeReader).removeUid(invalidUid);
}
@Test
@@ -1142,7 +1138,6 @@
}
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
mBatteryStatsImpl.getUidStats().get(invalidUid));
- verify(mCpuUidActiveTimeReader).removeUid(invalidUid);
}
@Test
@@ -1259,7 +1254,6 @@
}
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
mBatteryStatsImpl.getUidStats().get(invalidUid));
- verify(mCpuUidClusterTimeReader).removeUid(invalidUid);
}
@Test
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 85b60f8..be1e2b2 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -127,6 +127,20 @@
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.networkstack",
+ sub_dir: "permissions",
+ src: "com.android.networkstack.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
+ name: "privapp_whitelist_com.android.networkstack.tethering",
+ sub_dir: "permissions",
+ src: "com.android.networkstack.tethering.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.provision",
system_ext_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml
new file mode 100644
index 0000000..f26a961
--- /dev/null
+++ b/data/etc/com.android.networkstack.tethering.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+
+<permissions>
+ <privapp-permissions package="com.android.networkstack.tethering">
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
+ <permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.networkstack.xml b/data/etc/com.android.networkstack.xml
new file mode 100644
index 0000000..06fec1c
--- /dev/null
+++ b/data/etc/com.android.networkstack.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+
+<permissions>
+ <privapp-permissions package="com.android.networkstack">
+ <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+ <permission name="android.permission.CONTROL_VPN"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+ <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
+ <permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
+ <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+ <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.READ_WIFI_CREDENTIAL"/>
+ <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 545a564..194c4a2 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -271,36 +271,6 @@
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
</privapp-permissions>
- <privapp-permissions package="com.android.networkstack">
- <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
- <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
- <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
- <permission name="android.permission.CONTROL_VPN"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
- <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
- <permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
- <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
- <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
- <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.READ_WIFI_CREDENTIAL"/>
- <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/>
- <permission name="android.permission.TETHER_PRIVILEGED"/>
- <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- </privapp-permissions>
-
- <privapp-permissions package="com.android.networkstack.tethering">
- <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
- <permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
- <permission name="android.permission.TETHER_PRIVILEGED"/>
- <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
- <permission name="android.permission.UPDATE_DEVICE_STATS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.server.telecom">
<permission name="android.permission.BIND_CONNECTION_SERVICE"/>
<permission name="android.permission.BIND_INCALL_SERVICE"/>
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 6c0981a..e5651e0 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -50,15 +50,17 @@
+ "}"
+ "const float PI = 3.1415926535897932384626;\n"
+ "\n"
+ + "float threshold(float v, float l, float h) {\n"
+ + " return step(l, v) * (1.0 - step(h, v));\n"
+ + "}\n"
+ "float sparkles(vec2 uv, float t) {\n"
+ " float n = triangleNoise(uv);\n"
+ " float s = 0.0;\n"
+ " for (float i = 0; i < 4; i += 1) {\n"
- + " float l = i * 0.01;\n"
- + " float h = l + 0.2;\n"
- + " float o = smoothstep(n - l, h, n);\n"
- + " o *= abs(sin(PI * o * (t + 0.55 * i)));\n"
- + " s += o;\n"
+ + " float l = i * 0.1;\n"
+ + " float h = l + 0.025;\n"
+ + " float o = sin(PI * (t + 0.35 * i));\n"
+ + " s += threshold(n + o, l, h);\n"
+ " }\n"
+ " return saturate(s) * in_sparkleColor.a;\n"
+ "}\n"
@@ -125,9 +127,6 @@
private static final double PI_ROTATE_RIGHT = Math.PI * 0.0078125;
private static final double PI_ROTATE_LEFT = Math.PI * -0.0078125;
- private float mNoisePhase;
- private float mProgress;
-
RippleShader() {
super(SHADER, false);
}
@@ -143,15 +142,6 @@
setUniform("in_maxRadius", radius);
}
- /**
- * Continuous offset used as noise phase.
- */
- public void setNoisePhase(float phase) {
- mNoisePhase = phase;
- setUniform("in_noisePhase", phase);
- updateTurbulence();
- }
-
public void setOrigin(float x, float y) {
setUniform("in_origin", new float[] {x, y});
}
@@ -161,18 +151,20 @@
}
public void setProgress(float progress) {
- mProgress = progress;
setUniform("in_progress", progress);
- updateTurbulence();
}
- private void updateTurbulence() {
- final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI);
- setUniform("in_turbulencePhase", turbulencePhase);
+ /**
+ * Continuous offset used as noise phase.
+ */
+ public void setNoisePhase(float phase) {
+ setUniform("in_noisePhase", phase * 0.001f);
//
// Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h
//
+ final float turbulencePhase = phase;
+ setUniform("in_turbulencePhase", turbulencePhase);
final float scale = 1.5f;
setUniform("in_tCircle1", new float[]{
(float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))),
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 1d392d2..0da2b51 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -85,6 +85,15 @@
}
}
+ /**
+ * @hide
+ */
+ public static void resetAvailableFonts() {
+ synchronized (LOCK) {
+ sAvailableFonts = null;
+ }
+ }
+
private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
try (FileInputStream file = new FileInputStream(fullPath)) {
final FileChannel fileChannel = file.getChannel();
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index 6bd0e0a..10df726 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell">
<!-- System permission required by WM Shell Task Organizer. -->
+ <uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 26f98d8..4c2863e 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -24,6 +24,9 @@
<!-- Animation duration for resizing of PIP. -->
<integer name="config_pipResizeAnimationDuration">425</integer>
+ <!-- Animation duration for crossfading of PIP (specifically to fade out the layer on top). -->
+ <integer name="config_pipCrossfadeAnimationDuration">150</integer>
+
<!-- Allow dragging the PIP to a location to close it -->
<bool name="config_pipEnableDismissDragToEdge">true</bool>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
index 6984ea45..006730d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -42,7 +42,7 @@
private final SyncTransactionQueue mSyncQueue;
- private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
+ private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
public FullscreenTaskListener(SyncTransactionQueue syncQueue) {
mSyncQueue = syncQueue;
@@ -50,14 +50,14 @@
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mLeashByTaskId.get(taskInfo.taskId) != null) {
+ if (mDataByTaskId.get(taskInfo.taskId) != null) {
throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
taskInfo.taskId);
- mLeashByTaskId.put(taskInfo.taskId, leash);
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
final Point positionInParent = taskInfo.positionInParent;
+ mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
mSyncQueue.runInSync(t -> {
// Reset several properties back to fullscreen (PiP, for example, leaves all these
// properties in a bad state).
@@ -72,45 +72,57 @@
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
+ final TaskData data = mDataByTaskId.get(taskInfo.taskId);
final Point positionInParent = taskInfo.positionInParent;
- mSyncQueue.runInSync(t -> {
- // Reset several properties back. For instance, when an Activity enters PiP with
- // multiple activities in the same task, a new task will be created from that Activity
- // and we want reset the leash of the original task.
- t.setPosition(leash, positionInParent.x, positionInParent.y);
- t.setWindowCrop(leash, null);
- });
+ if (!positionInParent.equals(data.positionInParent)) {
+ data.positionInParent.set(positionInParent.x, positionInParent.y);
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(data.surface, positionInParent.x, positionInParent.y);
+ });
+ }
}
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- if (mLeashByTaskId.get(taskInfo.taskId) == null) {
+ if (mDataByTaskId.get(taskInfo.taskId) == null) {
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
return;
}
- mLeashByTaskId.remove(taskInfo.taskId);
+ mDataByTaskId.remove(taskInfo.taskId);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
taskInfo.taskId);
}
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- if (!mLeashByTaskId.contains(taskId)) {
+ if (!mDataByTaskId.contains(taskId)) {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
- b.setParent(mLeashByTaskId.get(taskId));
+ b.setParent(mDataByTaskId.get(taskId).surface);
}
@Override
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + this);
- pw.println(innerPrefix + mLeashByTaskId.size() + " Tasks");
+ pw.println(innerPrefix + mDataByTaskId.size() + " Tasks");
}
@Override
public String toString() {
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
}
+
+ /**
+ * Per-task data for each managed task.
+ */
+ private static class TaskData {
+ public final SurfaceControl surface;
+ public final Point positionInParent;
+
+ public TaskData(SurfaceControl surface, Point positionInParent) {
+ this.surface = surface;
+ this.positionInParent = positionInParent;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index d451f4a..0b941b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -16,14 +16,14 @@
package com.android.wm.shell;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
@@ -145,7 +145,7 @@
}
final int taskId = new Integer(args[2]);
final int sideStagePosition = args.length > 3
- ? new Integer(args[3]) : STAGE_POSITION_BOTTOM_OR_RIGHT;
+ ? new Integer(args[3]) : SPLIT_POSITION_BOTTOM_OR_RIGHT;
mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition));
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index eb82c6d..e6d088e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -20,11 +20,15 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import android.app.ActivityManager;
import android.graphics.Rect;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -35,6 +39,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.split.SplitLayout;
@@ -45,7 +50,7 @@
* {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
* Also includes all UI for managing the pair like the divider.
*/
-class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChangeListener {
+class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayoutHandler {
private static final String TAG = AppPair.class.getSimpleName();
private ActivityManager.RunningTaskInfo mRootTaskInfo;
@@ -54,6 +59,9 @@
private SurfaceControl mTaskLeash1;
private ActivityManager.RunningTaskInfo mTaskInfo2;
private SurfaceControl mTaskLeash2;
+ private SurfaceControl mDimLayer1;
+ private SurfaceControl mDimLayer2;
+ private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final AppPairsController mController;
private final SyncTransactionQueue mSyncQueue;
@@ -101,7 +109,8 @@
mSplitLayout = new SplitLayout(TAG + "SplitDivider",
mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
mRootTaskInfo.configuration, this /* layoutChangeListener */,
- b -> b.setParent(mRootTaskLeash), mDisplayImeController);
+ b -> b.setParent(mRootTaskLeash), mDisplayImeController,
+ mController.getTaskOrganizer());
final WindowContainerToken token1 = task1.token;
final WindowContainerToken token2 = task2.token;
@@ -153,9 +162,13 @@
} else if (taskInfo.taskId == getTaskId1()) {
mTaskInfo1 = taskInfo;
mTaskLeash1 = leash;
+ mSyncQueue.runInSync(t -> mDimLayer1 =
+ SurfaceUtils.makeDimLayer(t, mTaskLeash1, "Dim layer", mSurfaceSession));
} else if (taskInfo.taskId == getTaskId2()) {
mTaskInfo2 = taskInfo;
mTaskLeash2 = leash;
+ mSyncQueue.runInSync(t -> mDimLayer2 =
+ SurfaceUtils.makeDimLayer(t, mTaskLeash2, "Dim layer", mSurfaceSession));
} else {
throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
}
@@ -182,6 +195,11 @@
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (!taskInfo.supportsMultiWindow) {
+ // Dismiss AppPair if the task no longer supports multi window.
+ mController.unpair(mRootTaskInfo.taskId);
+ return;
+ }
if (taskInfo.taskId == getRootTaskId()) {
if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
mSyncQueue.runInSync(t -> {
@@ -208,12 +226,31 @@
}
@Override
+ public int getSplitItemPosition(WindowContainerToken token) {
+ if (token == null) {
+ return SPLIT_POSITION_UNDEFINED;
+ }
+
+ if (token.equals(mTaskInfo1.getToken())) {
+ return SPLIT_POSITION_TOP_OR_LEFT;
+ } else if (token.equals(mTaskInfo2.getToken())) {
+ return SPLIT_POSITION_BOTTOM_OR_RIGHT;
+ }
+
+ return SPLIT_POSITION_UNDEFINED;
+ }
+
+ @Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
if (taskInfo.taskId == getRootTaskId()) {
// We don't want to release this object back to the pool since the root task went away.
mController.unpair(mRootTaskInfo.taskId, false /* releaseToPool */);
- } else if (taskInfo.taskId == getTaskId1() || taskInfo.taskId == getTaskId2()) {
+ } else if (taskInfo.taskId == getTaskId1()) {
mController.unpair(mRootTaskInfo.taskId);
+ mSyncQueue.runInSync(t -> t.remove(mDimLayer1));
+ } else if (taskInfo.taskId == getTaskId2()) {
+ mController.unpair(mRootTaskInfo.taskId);
+ mSyncQueue.runInSync(t -> t.remove(mDimLayer2));
}
}
@@ -259,40 +296,16 @@
@Override
public void onBoundsChanging(SplitLayout layout) {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) return;
- final Rect dividerBounds = layout.getDividerBounds();
- final Rect bounds1 = layout.getBounds1();
- final Rect bounds2 = layout.getBounds2();
- mSyncQueue.runInSync(t -> t
- .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
- .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
- .setPosition(mTaskLeash2, bounds2.left, bounds2.top)
- // Sets crop to prevent visible region of tasks overlap with each other when
- // re-positioning surfaces while resizing.
- .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height())
- .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height()));
+ mSyncQueue.runInSync(t ->
+ layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
@Override
public void onBoundsChanged(SplitLayout layout) {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) return;
- final Rect dividerBounds = layout.getDividerBounds();
- final Rect bounds1 = layout.getBounds1();
- final Rect bounds2 = layout.getBounds2();
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mTaskInfo1.token, bounds1)
- .setBounds(mTaskInfo2.token, bounds2);
- mController.getTaskOrganizer().applyTransaction(wct);
- mSyncQueue.runInSync(t -> t
- // Resets layer of divider bar to make sure it is always on top.
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
- .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
- .setPosition(mTaskLeash2, bounds2.left, bounds2.top)
- // Resets crop to apply new surface bounds directly.
- .setWindowCrop(mTaskLeash1, null)
- .setWindowCrop(mTaskLeash2, null));
+ layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t ->
+ layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java
new file mode 100644
index 0000000..55c5125
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+/**
+ * Helpers for handling surface.
+ */
+public class SurfaceUtils {
+ /** Creates a dim layer above indicated host surface. */
+ public static SurfaceControl makeDimLayer(SurfaceControl.Transaction t, SurfaceControl host,
+ String name, SurfaceSession surfaceSession) {
+ SurfaceControl dimLayer = new SurfaceControl.Builder(surfaceSession)
+ .setParent(host)
+ .setColorLayer()
+ .setName(name)
+ .setCallsite("SurfaceUtils.makeDimLayer")
+ .build();
+ t.setLayer(dimLayer, Integer.MAX_VALUE).setColor(dimLayer, new float[]{0f, 0f, 0f});
+ return dimLayer;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 442e7a4..a920f9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -36,13 +36,11 @@
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.DisplayImeController;
/**
* Divider for multi window splits.
*/
-public class DividerView extends FrameLayout implements View.OnTouchListener,
- DisplayImeController.ImePositionProcessor {
+public class DividerView extends FrameLayout implements View.OnTouchListener {
public static final long TOUCH_ANIMATION_DURATION = 150;
public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
@@ -99,12 +97,6 @@
}
@Override
- public void onImeVisibilityChanged(int displayId, boolean isShowing) {
- if (displayId != getDisplay().getDisplayId()) return;
- setInteractive(!isShowing);
- }
-
- @Override
public boolean onTouch(View v, MotionEvent event) {
if (mSplitLayout == null || !mInteractive) {
return false;
@@ -217,7 +209,7 @@
mViewHost.relayout(lp);
}
- private void setInteractive(boolean interactive) {
+ void setInteractive(boolean interactive) {
if (interactive == mInteractive) return;
mInteractive = interactive;
releaseTouching();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index d318a5a..e42f511 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -25,16 +25,22 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayImeController;
@@ -42,7 +48,32 @@
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
* divide position changes.
*/
-public class SplitLayout {
+public final class SplitLayout {
+ /**
+ * Split position isn't specified normally meaning to use what ever it is currently set to.
+ */
+ public static final int SPLIT_POSITION_UNDEFINED = -1;
+
+ /**
+ * Specifies that a split is positioned at the top half of the screen if
+ * in portrait mode or at the left half of the screen if in landscape mode.
+ */
+ public static final int SPLIT_POSITION_TOP_OR_LEFT = 0;
+
+ /**
+ * Specifies that a split is positioned at the bottom half of the screen if
+ * in portrait mode or at the right half of the screen if in landscape mode.
+ */
+ public static final int SPLIT_POSITION_BOTTOM_OR_RIGHT = 1;
+
+ @IntDef(prefix = {"SPLIT_POSITION_"}, value = {
+ SPLIT_POSITION_UNDEFINED,
+ SPLIT_POSITION_TOP_OR_LEFT,
+ SPLIT_POSITION_BOTTOM_OR_RIGHT
+ })
+ public @interface SplitPosition {
+ }
+
private final int mDividerWindowWidth;
private final int mDividerInsets;
private final int mDividerSize;
@@ -51,8 +82,11 @@
private final Rect mDividerBounds = new Rect();
private final Rect mBounds1 = new Rect();
private final Rect mBounds2 = new Rect();
- private final LayoutChangeListener mLayoutChangeListener;
+ private final SplitLayoutHandler mSplitLayoutHandler;
private final SplitWindowManager mSplitWindowManager;
+ private final DisplayImeController mDisplayImeController;
+ private final ImePositionProcessor mImePositionProcessor;
+ private final ShellTaskOrganizer mTaskOrganizer;
private Context mContext;
private DividerSnapAlgorithm mDividerSnapAlgorithm;
@@ -60,18 +94,21 @@
private boolean mInitialized = false;
public SplitLayout(String windowName, Context context, Configuration configuration,
- LayoutChangeListener layoutChangeListener,
+ SplitLayoutHandler splitLayoutHandler,
SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
- DisplayImeController displayImeController) {
+ DisplayImeController displayImeController, ShellTaskOrganizer taskOrganizer) {
mContext = context.createConfigurationContext(configuration);
- mLayoutChangeListener = layoutChangeListener;
+ mSplitLayoutHandler = splitLayoutHandler;
+ mDisplayImeController = displayImeController;
mSplitWindowManager = new SplitWindowManager(
- windowName, mContext, configuration, parentContainerCallbacks,
- displayImeController);
+ windowName, mContext, configuration, parentContainerCallbacks);
+ mTaskOrganizer = taskOrganizer;
+ mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
- mDividerWindowWidth = context.getResources().getDimensionPixelSize(
+ final Resources resources = context.getResources();
+ mDividerWindowWidth = resources.getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
- mDividerInsets = context.getResources().getDimensionPixelSize(
+ mDividerInsets = resources.getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
mDividerSize = mDividerWindowWidth - mDividerInsets * 2;
@@ -82,17 +119,17 @@
/** Gets bounds of the primary split. */
public Rect getBounds1() {
- return mBounds1;
+ return new Rect(mBounds1);
}
/** Gets bounds of the secondary split. */
public Rect getBounds2() {
- return mBounds2;
+ return new Rect(mBounds2);
}
/** Gets bounds of divider window. */
public Rect getDividerBounds() {
- return mDividerBounds;
+ return new Rect(mDividerBounds);
}
/** Returns leash of the current divider bar. */
@@ -153,6 +190,7 @@
if (mInitialized) return;
mInitialized = true;
mSplitWindowManager.init(this);
+ mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
/** Releases the surface holding the current {@link DividerView}. */
@@ -160,6 +198,8 @@
if (!mInitialized) return;
mInitialized = false;
mSplitWindowManager.release();
+ mDisplayImeController.removePositionProcessor(mImePositionProcessor);
+ mImePositionProcessor.reset();
}
/**
@@ -168,14 +208,14 @@
*/
void updateDivideBounds(int position) {
updateBounds(position);
- mLayoutChangeListener.onBoundsChanging(this);
mSplitWindowManager.setResizingSplits(true);
+ mSplitLayoutHandler.onBoundsChanging(this);
}
void setDividePosition(int position) {
mDividePosition = position;
updateBounds(mDividePosition);
- mLayoutChangeListener.onBoundsChanged(this);
+ mSplitLayoutHandler.onBoundsChanged(this);
mSplitWindowManager.setResizingSplits(false);
}
@@ -192,11 +232,11 @@
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.flag) {
case FLAG_DISMISS_START:
- mLayoutChangeListener.onSnappedToDismiss(false /* bottomOrRight */);
+ mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */);
mSplitWindowManager.setResizingSplits(false);
break;
case FLAG_DISMISS_END:
- mLayoutChangeListener.onSnappedToDismiss(true /* bottomOrRight */);
+ mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */);
mSplitWindowManager.setResizingSplits(false);
break;
default:
@@ -206,7 +246,7 @@
}
void onDoubleTappedDivider() {
- mLayoutChangeListener.onDoubleTappedDivider();
+ mSplitLayoutHandler.onDoubleTappedDivider();
}
/**
@@ -265,8 +305,38 @@
return bounds.width() > bounds.height();
}
- /** Listens layout change event. */
- public interface LayoutChangeListener {
+ /** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */
+ public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
+ SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+ final Rect dividerBounds = mImePositionProcessor.adjustForIme(mDividerBounds);
+ final Rect bounds1 = mImePositionProcessor.adjustForIme(mBounds1);
+ final Rect bounds2 = mImePositionProcessor.adjustForIme(mBounds2);
+ final SurfaceControl dividerLeash = getDividerLeash();
+ if (dividerLeash != null) {
+ t.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+ // Resets layer of divider bar to make sure it is always on top.
+ .setLayer(dividerLeash, Integer.MAX_VALUE);
+ }
+
+ t.setPosition(leash1, bounds1.left, bounds1.top)
+ .setWindowCrop(leash1, bounds1.width(), bounds1.height());
+
+ t.setPosition(leash2, bounds2.left, bounds2.top)
+ .setWindowCrop(leash2, bounds2.width(), bounds2.height());
+
+ mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2);
+ }
+
+ /** Apply recorded task layout to the {@link WindowContainerTransaction}. */
+ public void applyTaskChanges(WindowContainerTransaction wct,
+ ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
+ wct.setBounds(task1.token, mImePositionProcessor.adjustForIme(mBounds1))
+ .setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
+ }
+
+ /** Handles layout change event. */
+ public interface SplitLayoutHandler {
+
/** Calls when dismissing split. */
void onSnappedToDismiss(boolean snappedToEnd);
@@ -279,5 +349,133 @@
/** Calls when user double tapped on the divider bar. */
default void onDoubleTappedDivider() {
}
+
+ /** Returns split position of the token. */
+ @SplitPosition
+ int getSplitItemPosition(WindowContainerToken token);
+ }
+
+ /** Records IME top offset changes and updates SplitLayout correspondingly. */
+ private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor {
+ /**
+ * Maximum size of an adjusted split bounds relative to original stack bounds. Used to
+ * restrict IME adjustment so that a min portion of top split remains visible.
+ */
+ private static final float ADJUSTED_SPLIT_FRACTION_MAX = 0.7f;
+ private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
+
+ private final int mDisplayId;
+
+ private int mYOffsetForIme;
+ private float mDimValue1;
+ private float mDimValue2;
+
+ private int mStartImeTop;
+ private int mEndImeTop;
+
+ private int mTargetYOffset;
+ private int mLastYOffset;
+ private float mTargetDim1;
+ private float mTargetDim2;
+ private float mLastDim1;
+ private float mLastDim2;
+
+ private ImePositionProcessor(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
+ if (displayId != mDisplayId) return 0;
+ final int imeTargetPosition = getImeTargetPosition();
+ if (!mInitialized || imeTargetPosition == SPLIT_POSITION_UNDEFINED) return 0;
+ mStartImeTop = showing ? hiddenTop : shownTop;
+ mEndImeTop = showing ? shownTop : hiddenTop;
+
+ // Update target dim values
+ mLastDim1 = mDimValue1;
+ mTargetDim1 = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT && showing
+ ? ADJUSTED_NONFOCUS_DIM : 0.0f;
+ mLastDim2 = mDimValue2;
+ mTargetDim2 = imeTargetPosition == SPLIT_POSITION_TOP_OR_LEFT && showing
+ ? ADJUSTED_NONFOCUS_DIM : 0.0f;
+
+ // Calculate target bounds offset for IME
+ mLastYOffset = mYOffsetForIme;
+ final boolean needOffset = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+ && !isFloating && !isLandscape(mRootBounds) && showing;
+ mTargetYOffset = needOffset ? getTargetYOffset() : 0;
+
+ // Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
+ // ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
+ // because DividerView won't receive onImeVisibilityChanged callback after it being
+ // re-inflated.
+ mSplitWindowManager.setInteractive(
+ !showing || imeTargetPosition == SPLIT_POSITION_UNDEFINED);
+
+ return 0;
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
+ if (displayId != mDisplayId) return;
+ onProgress(getProgress(imeTop));
+ mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ }
+
+ @Override
+ public void onImeEndPositioning(int displayId, boolean cancel,
+ SurfaceControl.Transaction t) {
+ if (displayId != mDisplayId || cancel) return;
+ onProgress(1.0f);
+ mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ }
+
+ private int getTargetYOffset() {
+ final int desireOffset = Math.abs(mEndImeTop - mStartImeTop);
+ // Make sure to keep at least 30% visible for the top split.
+ final int maxOffset = (int) (mBounds1.height() * ADJUSTED_SPLIT_FRACTION_MAX);
+ return -Math.min(desireOffset, maxOffset);
+ }
+
+ @SplitPosition
+ private int getImeTargetPosition() {
+ final WindowContainerToken token = mTaskOrganizer.getImeTarget(mDisplayId);
+ return mSplitLayoutHandler.getSplitItemPosition(token);
+ }
+
+ private float getProgress(int currImeTop) {
+ return ((float) currImeTop - mStartImeTop) / (mEndImeTop - mStartImeTop);
+ }
+
+ private void onProgress(float progress) {
+ mDimValue1 = getProgressValue(mLastDim1, mTargetDim1, progress);
+ mDimValue2 = getProgressValue(mLastDim2, mTargetDim2, progress);
+ mYOffsetForIme =
+ (int) getProgressValue((float) mLastYOffset, (float) mTargetYOffset, progress);
+ }
+
+ private float getProgressValue(float start, float end, float progress) {
+ return start + (end - start) * progress;
+ }
+
+ private void reset() {
+ mYOffsetForIme = 0;
+ mDimValue1 = mDimValue2 = 0.0f;
+ }
+
+ /* Adjust bounds with IME offset. */
+ private Rect adjustForIme(Rect bounds) {
+ final Rect temp = new Rect(bounds);
+ if (mYOffsetForIme != 0) temp.offset(0, mYOffsetForIme);
+ return temp;
+ }
+
+ private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1,
+ SurfaceControl dimLayer2) {
+ t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
+ t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index f6efb01..0cea0ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -46,7 +46,6 @@
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayImeController;
/**
* Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split.
@@ -55,7 +54,6 @@
private static final String TAG = SplitWindowManager.class.getSimpleName();
private final String mWindowName;
- private final DisplayImeController mDisplayImeController;
private final ParentContainerCallbacks mParentContainerCallbacks;
private Context mContext;
private SurfaceControlViewHost mViewHost;
@@ -68,13 +66,11 @@
}
public SplitWindowManager(String windowName, Context context, Configuration config,
- ParentContainerCallbacks parentContainerCallbacks,
- DisplayImeController displayImeController) {
+ ParentContainerCallbacks parentContainerCallbacks) {
super(config, null /* rootSurface */, null /* hostInputToken */);
mContext = context.createConfigurationContext(config);
mParentContainerCallbacks = parentContainerCallbacks;
mWindowName = windowName;
- mDisplayImeController = displayImeController;
}
@Override
@@ -128,7 +124,6 @@
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
mViewHost.setView(mDividerView, lp);
mDividerView.setup(splitLayout, mViewHost);
- mDisplayImeController.addPositionProcessor(mDividerView);
}
/**
@@ -137,7 +132,6 @@
*/
void release() {
if (mDividerView != null) {
- mDisplayImeController.removePositionProcessor(mDividerView);
mDividerView = null;
}
@@ -152,6 +146,11 @@
}
}
+ void setInteractive(boolean interactive) {
+ if (mDividerView == null) return;
+ mDividerView.setInteractive(interactive);
+ }
+
void setResizingSplits(boolean resizing) {
if (resizing == mResizingSplits) return;
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 9a09ca4..9bcc3ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -29,14 +29,14 @@
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.Intent.EXTRA_USER;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -64,7 +64,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.splitscreen.SplitScreen.StagePosition;
+import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -203,10 +203,10 @@
final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;
@StageType int stage = STAGE_TYPE_UNDEFINED;
- @StagePosition int position = STAGE_POSITION_UNDEFINED;
+ @SplitPosition int position = SPLIT_POSITION_UNDEFINED;
if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) {
// Update launch options for the split side we are targeting.
- position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
+ position = leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
if (!inSplitScreen) {
// Launch in the side stage if we are not in split-screen already.
stage = STAGE_TYPE_SIDE;
@@ -219,7 +219,7 @@
}
private void startClipDescription(ClipDescription description, Intent intent,
- @StageType int stage, @StagePosition int position) {
+ @StageType int stage, @SplitPosition int position) {
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
@@ -291,12 +291,12 @@
* Interface for actually committing the task launches.
*/
public interface Starter {
- void startTask(int taskId, @StageType int stage, @StagePosition int position,
+ void startTask(int taskId, @StageType int stage, @SplitPosition int position,
@Nullable Bundle options);
void startShortcut(String packageName, String shortcutId, @StageType int stage,
- @StagePosition int position, @Nullable Bundle options, UserHandle user);
+ @SplitPosition int position, @Nullable Bundle options, UserHandle user);
void startIntent(PendingIntent intent, Intent fillInIntent,
- @StageType int stage, @StagePosition int position,
+ @StageType int stage, @SplitPosition int position,
@Nullable Bundle options);
void enterSplitScreen(int taskId, boolean leftOrTop);
void exitSplitScreen();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index 60f7ee2..0f16c8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -685,9 +685,9 @@
mTmpRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom());
if (isHorizontalDivision()) {
- mTmpRect.offsetTo(0, mDividerPositionY);
+ mTmpRect.offsetTo(mHandle.getLeft(), mDividerPositionY);
} else {
- mTmpRect.offsetTo(mDividerPositionX, 0);
+ mTmpRect.offsetTo(mDividerPositionX, mHandle.getTop());
}
mWindowManagerProxy.setTouchRegion(mTmpRect);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
index 9eacaec..ee2202a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
@@ -577,7 +577,7 @@
mSplits.getSplitTransitions().dismissSplit(
mSplits, mSplitLayout, !toPrimaryTask, snapped);
} else {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
onDismissSplit();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
index cf35656..86bf3ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
@@ -38,6 +38,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.transition.Transitions;
@@ -70,9 +71,9 @@
private final LegacySplitScreenTransitions mSplitTransitions;
LegacySplitScreenTaskListener(LegacySplitScreenController splitScreenController,
- ShellTaskOrganizer shellTaskOrganizer,
- Transitions transitions,
- SyncTransactionQueue syncQueue) {
+ ShellTaskOrganizer shellTaskOrganizer,
+ Transitions transitions,
+ SyncTransactionQueue syncQueue) {
mSplitScreenController = splitScreenController;
mTaskOrganizer = shellTaskOrganizer;
mSplitTransitions = new LegacySplitScreenTransitions(splitScreenController.mTransactionPool,
@@ -146,21 +147,11 @@
ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG);
// Initialize dim surfaces:
- mPrimaryDim = new SurfaceControl.Builder(mSurfaceSession)
- .setParent(mPrimarySurface).setColorLayer()
- .setName("Primary Divider Dim")
- .setCallsite("SplitScreenTaskOrganizer.onTaskAppeared")
- .build();
- mSecondaryDim = new SurfaceControl.Builder(mSurfaceSession)
- .setParent(mSecondarySurface).setColorLayer()
- .setName("Secondary Divider Dim")
- .setCallsite("SplitScreenTaskOrganizer.onTaskAppeared")
- .build();
SurfaceControl.Transaction t = getTransaction();
- t.setLayer(mPrimaryDim, Integer.MAX_VALUE);
- t.setColor(mPrimaryDim, new float[]{0f, 0f, 0f});
- t.setLayer(mSecondaryDim, Integer.MAX_VALUE);
- t.setColor(mSecondaryDim, new float[]{0f, 0f, 0f});
+ mPrimaryDim = SurfaceUtils.makeDimLayer(
+ t, mPrimarySurface, "Primary Divider Dim", mSurfaceSession);
+ mSecondaryDim = SurfaceUtils.makeDimLayer(
+ t, mSecondarySurface, "Secondary Divider Dim", mSurfaceSession);
t.apply();
releaseTransaction(t);
}
@@ -203,6 +194,22 @@
return;
}
synchronized (this) {
+ if (!taskInfo.supportsMultiWindow) {
+ if (mSplitScreenController.isDividerVisible()) {
+ // Dismiss the split screen if the task no longer supports multi window.
+ if (taskInfo.taskId == mPrimary.taskId
+ || taskInfo.parentTaskId == mPrimary.taskId) {
+ // If the primary is focused, dismiss to primary.
+ mSplitScreenController
+ .startDismissSplit(taskInfo.isFocused /* toPrimaryTask */);
+ } else {
+ // If the secondary is not focused, dismiss to primary.
+ mSplitScreenController
+ .startDismissSplit(!taskInfo.isFocused /* toPrimaryTask */);
+ }
+ }
+ return;
+ }
if (taskInfo.hasParentTask()) {
// changed messages are noisy since it reports on every ensureVisibility. This
// conflicts with legacy app-transitions which "swaps" the position to a
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 7e5fd92..1ae2636 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
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
@@ -203,8 +204,10 @@
}
OneHandedTransitionAnimator addOneHandedAnimationCallback(
- OneHandedAnimationCallback callback) {
- mOneHandedAnimationCallbacks.add(callback);
+ @Nullable OneHandedAnimationCallback callback) {
+ if (callback != null) {
+ mOneHandedAnimationCallbacks.add(callback);
+ }
return this;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index e506542..49266ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -217,7 +217,7 @@
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
OneHandedState transitionState = new OneHandedState();
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
- displayLayout, windowManager, mainExecutor);
+ displayLayout, windowManager, settingsUtil, mainExecutor);
OneHandedAnimationController animationController =
new OneHandedAnimationController(context);
OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
@@ -299,6 +299,8 @@
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityStateChangeListener);
+
+ mState.addSListeners(mTutorialHandler);
}
public OneHanded asOneHanded() {
@@ -627,13 +629,13 @@
}
private void onConfigChanged(Configuration newConfig) {
- if (mTutorialHandler != null) {
- if (!mIsOneHandedEnabled
- || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
- return;
- }
- mTutorialHandler.onConfigurationChanged(newConfig);
+ if (mTutorialHandler == null) {
+ return;
}
+ if (!mIsOneHandedEnabled || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ return;
+ }
+ mTutorialHandler.onConfigurationChanged();
}
private void onUserSwitch(int newUserId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index bb68224..90fc823 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -29,7 +29,7 @@
import java.lang.annotation.RetentionPolicy;
/**
- * APIs for querying or updating one handed settings .
+ * APIs for querying or updating one handed settings.
*/
public final class OneHandedSettingsUtil {
private static final String TAG = "OneHandedSettingsUtil";
@@ -62,7 +62,7 @@
public static final int ONE_HANDED_TIMEOUT_LONG_IN_SECONDS = 12;
/**
- * Register one handed preference settings observer
+ * Registers one handed preference settings observer
*
* @param key Setting key to monitor in observer
* @param resolver ContentResolver of context
@@ -82,7 +82,7 @@
}
/**
- * Unregister one handed preference settings observer
+ * Unregisters one handed preference settings observer.
*
* @param resolver ContentResolver of context
* @param observer preference key change observer
@@ -95,7 +95,7 @@
}
/**
- * Query one handed enable or disable flag from Settings provider.
+ * Queries one handed enable or disable flag from Settings provider.
*
* @return enable or disable one handed mode flag.
*/
@@ -105,7 +105,7 @@
}
/**
- * Query taps app to exit config from Settings provider.
+ * Queries taps app to exit config from Settings provider.
*
* @return enable or disable taps app exit.
*/
@@ -115,7 +115,7 @@
}
/**
- * Query timeout value from Settings provider. Default is
+ * Queries timeout value from Settings provider. Default is.
* {@link OneHandedSettingsUtil#ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS}
*
* @return timeout value in seconds.
@@ -135,10 +135,31 @@
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0, userId) == 1;
}
+
/**
- * Sets one handed activated or not to notify state for shortcut
+ * Queries tutorial shown counts from Settings provider. Default is 0.
*
- * @return activated or not
+ * @return counts tutorial shown counts.
+ */
+ public int getTutorialShownCounts(ContentResolver resolver, int userId) {
+ return Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0, userId);
+ }
+
+ /**
+ * Sets tutorial shown counts.
+ *
+ * @return true if the value was set, false on database errors.
+ */
+ public boolean setTutorialShownCounts(ContentResolver resolver, int shownCounts, int userId) {
+ return Settings.Secure.putIntForUser(resolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, shownCounts, userId);
+ }
+
+ /**
+ * Sets one handed activated or not to notify state for shortcut.
+ *
+ * @return true if one handed mode is activated.
*/
public boolean getOneHandedModeActivated(ContentResolver resolver, int userId) {
return Settings.Secure.getIntForUser(resolver,
@@ -146,9 +167,9 @@
}
/**
- * Sets one handed activated or not to notify state for shortcut
+ * Sets one handed activated or not to notify state for shortcut.
*
- * @return activated or not
+ * @return true if the value was set, false on database errors.
*/
public boolean setOneHandedModeActivated(ContentResolver resolver, int state, int userId) {
return Settings.Secure.putIntForUser(resolver,
@@ -167,6 +188,8 @@
pw.println(getSettingsTapsAppToExit(resolver, userId));
pw.print(innerPrefix + "shortcutActivated=");
pw.println(getOneHandedModeActivated(resolver, userId));
+ pw.print(innerPrefix + "tutorialShownCounts=");
+ pw.println(getTutorialShownCounts(resolver, userId));
}
public OneHandedSettingsUtil() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java
index facc4bd..47bb99d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java
@@ -21,6 +21,8 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
Represents current OHM state by following steps, a generic CUJ is
@@ -28,13 +30,13 @@
*/
public class OneHandedState {
/** DEFAULT STATE after OHM feature initialized. */
- public static final int STATE_NONE = 0x00000000;
+ public static final int STATE_NONE = 0;
/** The state flag set when user trigger OHM. */
- public static final int STATE_ENTERING = 0x00000001;
+ public static final int STATE_ENTERING = 1;
/** The state flag set when transitioning */
- public static final int STATE_ACTIVE = 0x00000002;
+ public static final int STATE_ACTIVE = 2;
/** The state flag set when user stop OHM feature. */
- public static final int STATE_EXITING = 0x00000004;
+ public static final int STATE_EXITING = 3;
@IntDef(prefix = { "STATE_" }, value = {
STATE_NONE,
@@ -54,9 +56,18 @@
private static final String TAG = OneHandedState.class.getSimpleName();
+ private List<OnStateChangedListener> mStateChangeListeners = new ArrayList<>();
+
+ /**
+ * Adds listener to be called back when one handed state changed.
+ * @param listener the listener to be called back
+ */
+ public void addSListeners(OnStateChangedListener listener) {
+ mStateChangeListeners.add(listener);
+ }
+
/**
* Gets current transition state of One handed mode.
- *
* @return The bitwise flags representing current states.
*/
public @State int getState() {
@@ -85,6 +96,9 @@
*/
public void setState(@State int newState) {
sCurrentState = newState;
+ if (!mStateChangeListeners.isEmpty()) {
+ mStateChangeListeners.forEach((listener) -> listener.onStateChanged(newState));
+ }
}
/** Dumps internal state. */
@@ -93,4 +107,14 @@
pw.println(TAG);
pw.println(innerPrefix + "sCurrentState=" + sCurrentState);
}
+
+ /**
+ * Gets notified when one handed state changed
+ *
+ * @see OneHandedState
+ */
+ public interface OnStateChangedListener {
+ /** Called when one handed state changed */
+ default void onStateChanged(@State int newState) {}
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index e8cee8a..6cee404 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -16,13 +16,19 @@
package com.android.wm.shell.onehanded;
+import static android.os.UserHandle.myUserId;
+
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.SystemProperties;
-import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -32,6 +38,7 @@
import androidx.annotation.NonNull;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
@@ -39,42 +46,33 @@
import java.io.PrintWriter;
/**
- * Manages the user tutorial handling for One Handed operations, including animations synchronized
- * with one-handed translation.
- * Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop
- * one handed gesture
+ * Handles tutorial visibility and synchronized transition for One Handed operations,
+ * TargetViewContainer only be created and attach to window when
+ * shown counts < {@link MAX_TUTORIAL_SHOW_COUNT}, and detach TargetViewContainer from window
+ * after exiting one handed mode.
*/
-public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
+public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
+ OneHandedState.OnStateChangedListener {
private static final String TAG = "OneHandedTutorialHandler";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
- private final WindowManager mWindowManager;
- private final String mPackageName;
+
private final float mTutorialHeightRatio;
+ private final WindowManager mWindowManager;
+ private final OneHandedSettingsUtil mSettingsUtil;
+ private final ShellExecutor mShellExecutor;
+
+ private boolean mCanShow;
+ private @OneHandedState.State int mCurrentState;
+ private int mShownCounts;
+ private int mTutorialAreaHeight;
private Context mContext;
- private Rect mDisplayBounds;
- private View mTutorialView;
private ContentResolver mContentResolver;
- private boolean mCanShowTutorial;
- private boolean mIsOneHandedMode;
-
- private enum ONE_HANDED_TRIGGER_STATE {
- UNSET, ENTERING, EXITING
- }
- /**
- * Current One-Handed trigger state.
- * Note: This is a dynamic state, whenever last state has been confirmed
- * (i.e. onStartFinished() or onStopFinished()), the state should be set "UNSET" at final.
- */
- private ONE_HANDED_TRIGGER_STATE mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
-
- /**
- * Container of the tutorial panel showing at outside region when one handed starting
- */
- private ViewGroup mTargetViewContainer;
- private int mTutorialAreaHeight;
+ private Rect mDisplayBounds;
+ private @Nullable View mTutorialView;
+ private @Nullable ViewGroup mTargetViewContainer;
private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() {
@Override
@@ -82,63 +80,51 @@
if (!canShowTutorial()) {
return;
}
- mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.setTransitionGroup(true);
mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight());
}
-
- @Override
- public void onOneHandedAnimationStart(
- OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- final float startValue = (float) animator.getStartValue();
- if (mTriggerState == ONE_HANDED_TRIGGER_STATE.UNSET) {
- mTriggerState = (startValue == 0f)
- ? ONE_HANDED_TRIGGER_STATE.ENTERING : ONE_HANDED_TRIGGER_STATE.EXITING;
- if (mCanShowTutorial && mTriggerState == ONE_HANDED_TRIGGER_STATE.ENTERING) {
- attachTurtorialTarget();
- }
- }
- }
};
public OneHandedTutorialHandler(Context context, DisplayLayout displayLayout,
- WindowManager windowManager, ShellExecutor mainExecutor) {
+ WindowManager windowManager, OneHandedSettingsUtil settingsUtil,
+ ShellExecutor mainExecutor) {
mContext = context;
- mWindowManager = windowManager;
- mPackageName = context.getPackageName();
mContentResolver = context.getContentResolver();
+ mWindowManager = windowManager;
+ mSettingsUtil = settingsUtil;
+ mShellExecutor = mainExecutor;
final float offsetPercentageConfig = context.getResources().getFraction(
R.fraction.config_one_handed_offset, 1, 1);
final int sysPropPercentageConfig = SystemProperties.getInt(
ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
mTutorialHeightRatio = sysPropPercentageConfig / 100.0f;
- onDisplayChanged(displayLayout);
- mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
- ? false : true;
- mIsOneHandedMode = false;
-
- mainExecutor.execute(() -> {
- recreateTutorialView(mContext);
- });
+ mShownCounts = mSettingsUtil.getTutorialShownCounts(mContentResolver, myUserId());
}
@Override
- public void onStartFinished(Rect bounds) {
- updateFinished(View.VISIBLE, 0f);
- updateTutorialCount();
- mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
- }
-
- @Override
- public void onStopFinished(Rect bounds) {
- updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight());
- removeTutorialFromWindowManager();
- mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
+ public void onStateChanged(int newState) {
+ mCurrentState = newState;
+ if (!canShowTutorial()) {
+ return;
+ }
+ switch (newState) {
+ case STATE_ENTERING:
+ createViewAndAttachToWindow(mContext);
+ break;
+ case STATE_ACTIVE:
+ case STATE_EXITING:
+ // no - op
+ break;
+ case STATE_NONE:
+ removeTutorialFromWindowManager(true /* increment */);
+ break;
+ default:
+ break;
+ }
}
/**
- * Called when onDisplayAdded() or onDisplayRemoved() callback
+ * Called when onDisplayAdded() or onDisplayRemoved() callback.
* @param displayLayout The latest {@link DisplayLayout} representing current displayId
*/
public void onDisplayChanged(DisplayLayout displayLayout) {
@@ -151,38 +137,32 @@
mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
}
- private void recreateTutorialView(Context context) {
- mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial,
- null);
- mTargetViewContainer = new FrameLayout(context);
- mTargetViewContainer.setClipChildren(false);
- mTargetViewContainer.addView(mTutorialView);
- mTargetViewContainer.setVisibility(mIsOneHandedMode ? View.VISIBLE : View.GONE);
- }
-
- private void updateFinished(int visible, float finalPosition) {
+ @VisibleForTesting
+ void createViewAndAttachToWindow(Context context) {
if (!canShowTutorial()) {
return;
}
- mIsOneHandedMode = (finalPosition == 0f) ? true : false;
- mTargetViewContainer.setVisibility(visible);
- mTargetViewContainer.setTranslationY(finalPosition);
+ mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null);
+ mTargetViewContainer = new FrameLayout(context);
+ mTargetViewContainer.setClipChildren(false);
+ mTargetViewContainer.addView(mTutorialView);
+
+ attachTargetToWindow();
}
- private void updateTutorialCount() {
- int showCount = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0);
- showCount = Math.min(MAX_TUTORIAL_SHOW_COUNT, showCount + 1);
- mCanShowTutorial = showCount < MAX_TUTORIAL_SHOW_COUNT;
- Settings.Secure.putInt(mContentResolver,
- Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
+ @VisibleForTesting
+ boolean setTutorialShownCountIncrement() {
+ if (!canShowTutorial()) {
+ return false;
+ }
+ mShownCounts += 1;
+ return mSettingsUtil.setTutorialShownCounts(mContentResolver, mShownCounts, myUserId());
}
/**
- * Adds the tutorial target view to the WindowManager and update its layout, so it's ready
- * to be animated in.
+ * Adds the tutorial target view to the WindowManager and update its layout.
*/
- private void attachTurtorialTarget() {
+ private void attachTargetToWindow() {
if (!mTargetViewContainer.isAttachedToWindow()) {
try {
mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
@@ -195,14 +175,18 @@
}
}
- private void removeTutorialFromWindowManager() {
- if (mTargetViewContainer.isAttachedToWindow()) {
+ @VisibleForTesting
+ void removeTutorialFromWindowManager(boolean increment) {
+ if (mTargetViewContainer != null && mTargetViewContainer.isAttachedToWindow()) {
mWindowManager.removeViewImmediate(mTargetViewContainer);
+ if (increment) {
+ setTutorialShownCountIncrement();
+ }
}
}
- OneHandedAnimationCallback getAnimationCallback() {
- return mAnimationCallback;
+ @Nullable OneHandedAnimationCallback getAnimationCallback() {
+ return canShowTutorial() ? mAnimationCallback : null /* Disabled */;
}
/**
@@ -222,38 +206,36 @@
return lp;
}
- void dump(@NonNull PrintWriter pw) {
- final String innerPrefix = " ";
- pw.println(TAG);
- pw.print(innerPrefix + "mTriggerState=");
- pw.println(mTriggerState);
- pw.print(innerPrefix + "mDisplayBounds=");
- pw.println(mDisplayBounds);
- pw.print(innerPrefix + "mTutorialAreaHeight=");
- pw.println(mTutorialAreaHeight);
- }
-
- private boolean canShowTutorial() {
- if (!mCanShowTutorial) {
- // Since canSHowTutorial() will be called in onAnimationUpdate() and we still need to
- // hide Tutorial text in the period of continuously onAnimationUpdate() API call,
- // so we have to hide mTargetViewContainer here.
- mTargetViewContainer.setVisibility(View.GONE);
- return false;
- }
- return true;
+ @VisibleForTesting
+ boolean canShowTutorial() {
+ return mCanShow = mShownCounts < MAX_TUTORIAL_SHOW_COUNT;
}
/**
* onConfigurationChanged events for updating tutorial text.
- * @param newConfig
*/
- public void onConfigurationChanged(Configuration newConfig) {
- if (!mCanShowTutorial) {
+ public void onConfigurationChanged() {
+ if (!canShowTutorial()) {
return;
}
- removeTutorialFromWindowManager();
- recreateTutorialView(mContext.createConfigurationContext(newConfig));
- attachTurtorialTarget();
+ removeTutorialFromWindowManager(false /* increment */);
+ if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
+ createViewAndAttachToWindow(mContext);
+ }
+ }
+
+ void dump(@NonNull PrintWriter pw) {
+ final String innerPrefix = " ";
+ pw.println(TAG);
+ pw.print(innerPrefix + "mCanShow=");
+ pw.println(mCanShow);
+ pw.print(innerPrefix + "mCurrentState=");
+ pw.println(mCurrentState);
+ pw.print(innerPrefix + "mDisplayBounds=");
+ pw.println(mDisplayBounds);
+ pw.print(innerPrefix + "mShownCounts=");
+ pw.println(mShownCounts);
+ pw.print(innerPrefix + "mTutorialAreaHeight=");
+ pw.println(mTutorialAreaHeight);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index a6ffa6e..ddc85f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip;
import android.app.PictureInPictureParams;
+import android.view.SurfaceControl;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
@@ -48,8 +49,10 @@
*
* @param componentName ComponentName represents the Activity
* @param destinationBounds the destination bounds the PiP window lands into
+ * @param overlay an optional overlay to fade out after entering PiP
*/
- oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2;
+ oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds,
+ in SurfaceControl overlay) = 2;
/**
* Sets listener to get pinned stack animation callbacks.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 0633330..b352871 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -147,6 +147,7 @@
private final PipUiEventLogger mPipUiEventLoggerLogger;
private final int mEnterAnimationDuration;
private final int mExitAnimationDuration;
+ private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Optional<LegacySplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
@@ -257,6 +258,12 @@
*/
private boolean mInSwipePipToHomeTransition;
+ /**
+ * An optional overlay used to mask content changing between an app in/out of PiP, only set if
+ * {@link #mInSwipePipToHomeTransition} is true.
+ */
+ private SurfaceControl mSwipePipToHomeOverlay;
+
public PipTaskOrganizer(Context context,
@NonNull SyncTransactionQueue syncTransactionQueue,
@NonNull PipBoundsState pipBoundsState,
@@ -280,6 +287,8 @@
.getInteger(R.integer.config_pipEnterAnimationDuration);
mExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipExitAnimationDuration);
+ mCrossFadeAnimationDuration = context.getResources()
+ .getInteger(R.integer.config_pipCrossfadeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
@@ -350,10 +359,12 @@
* Callback when launcher finishes swipe-pip-to-home operation.
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
*/
- public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+ SurfaceControl overlay) {
// do nothing if there is no startSwipePipToHome being called before
if (mInSwipePipToHomeTransition) {
mPipBoundsState.setBounds(destinationBounds);
+ mSwipePipToHomeOverlay = overlay;
}
}
@@ -599,6 +610,7 @@
private void onEndOfSwipePipToHomeTransition() {
final Rect destinationBounds = mPipBoundsState.getBounds();
+ final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
@@ -607,8 +619,14 @@
// Ensure menu's settled in its final bounds first.
finishResizeForMenu(destinationBounds);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+
+ // Remove the swipe to home overlay
+ if (swipeToHomeOverlay != null) {
+ fadeOutAndRemoveOverlay(swipeToHomeOverlay);
+ }
}, tx);
mInSwipePipToHomeTransition = false;
+ mSwipePipToHomeOverlay = null;
}
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@@ -1139,25 +1157,7 @@
mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
// Start animation to fade out the snapshot.
- final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
- animator.setDuration(mEnterAnimationDuration);
- animator.addUpdateListener(animation -> {
- final float alpha = (float) animation.getAnimatedValue();
- final SurfaceControl.Transaction transaction =
- mSurfaceControlTransactionFactory.getTransaction();
- transaction.setAlpha(snapshotSurface, alpha);
- transaction.apply();
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.remove(snapshotSurface);
- tx.apply();
- }
- });
- animator.start();
+ fadeOutAndRemoveOverlay(snapshotSurface);
});
} else {
applyFinishBoundsResize(wct, direction);
@@ -1301,6 +1301,35 @@
}
/**
+ * Fades out and removes an overlay surface.
+ */
+ private void fadeOutAndRemoveOverlay(SurfaceControl surface) {
+ if (surface == null) {
+ return;
+ }
+
+ final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
+ animator.setDuration(mCrossFadeAnimationDuration);
+ animator.addUpdateListener(animation -> {
+ final float alpha = (float) animation.getAnimatedValue();
+ final SurfaceControl.Transaction transaction =
+ mSurfaceControlTransactionFactory.getTransaction();
+ transaction.setAlpha(surface, alpha);
+ transaction.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ tx.remove(surface);
+ tx.apply();
+ }
+ });
+ animator.start();
+ }
+
+ /**
* Dumps internal states.
*/
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 91e3887..f80b161 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -44,6 +44,7 @@
import android.util.Size;
import android.util.Slog;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
@@ -557,8 +558,9 @@
return entryBounds;
}
- private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
- mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds);
+ private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+ SurfaceControl overlay) {
+ mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds, overlay);
}
@Override
@@ -850,10 +852,11 @@
}
@Override
- public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+ SurfaceControl overlay) {
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
(controller) -> {
- controller.stopSwipePipToHome(componentName, destinationBounds);
+ controller.stopSwipePipToHome(componentName, destinationBounds, overlay);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java
index f8125fd..23153be72 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java
@@ -27,6 +27,7 @@
private static final int PINCH_RESIZE_MAX_ANGLE_ROTATION = 45;
private static final float OVERROTATE_DAMP_FACTOR = 0.4f;
private static final float ANGLE_THRESHOLD = 5f;
+ private static final float OVERRESIZE_DAMP_FACTOR = 0.25f;
private final PointF mTmpDownVector = new PointF();
private final PointF mTmpLastVector = new PointF();
@@ -46,7 +47,10 @@
lastSecondPoint.y - lastPoint.y);
float minScale = getMinScale(initialBounds, minSize);
float maxScale = getMaxScale(initialBounds, maxSize);
- float scale = Math.max(minScale, Math.min(maxScale, dist / downDist));
+ float overStretchMin = minScale - dist / downDist > 0 ? minScale - dist / downDist : 0;
+ float overStretchMax = dist / downDist - maxScale > 0 ? dist / downDist - maxScale : 0;
+ float scale = Math.max(minScale - overStretchMin * OVERRESIZE_DAMP_FACTOR,
+ Math.min(maxScale + overStretchMax * OVERRESIZE_DAMP_FACTOR, dist / downDist));
// Scale the bounds by the change in distance between the points
resizeBoundsOut.set(initialBounds);
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 0878f54..f9a196d 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
@@ -383,14 +383,17 @@
return;
}
+ final Rect pipBounds = mPipBoundsState.getBounds();
if (action == MotionEvent.ACTION_POINTER_DOWN) {
- if (mFirstIndex == -1 && mSecondIndex == -1) {
+ if (mFirstIndex == -1 && mSecondIndex == -1
+ && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0))
+ && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) {
mAllowGesture = true;
mFirstIndex = 0;
mSecondIndex = 1;
mDownPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
mDownSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
- mDownBounds.set(mPipBoundsState.getBounds());
+ mDownBounds.set(pipBounds);
mLastPoint.set(mDownPoint);
mLastSecondPoint.set(mLastSecondPoint);
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 8f9dcef..f2e250a 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
@@ -472,17 +472,20 @@
float aspectRatio) {
final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(),
mPipBoundsState.getDisplayBounds().height());
- final int totalPadding = insetBounds.left * 2;
+ final int totalHorizontalPadding = insetBounds.left
+ + (mPipBoundsState.getDisplayBounds().width() - insetBounds.right);
+ final int totalVerticalPadding = insetBounds.top
+ + (mPipBoundsState.getDisplayBounds().height() - insetBounds.bottom);
final int minWidth, minHeight, maxWidth, maxHeight;
if (aspectRatio > 1f) {
minWidth = (int) Math.min(normalBounds.width(), shorterLength * MINIMUM_SIZE_PERCENT);
minHeight = (int) (minWidth / aspectRatio);
- maxWidth = (int) Math.max(normalBounds.width(), shorterLength - totalPadding);
+ maxWidth = (int) Math.max(normalBounds.width(), shorterLength - totalHorizontalPadding);
maxHeight = (int) (maxWidth / aspectRatio);
} else {
minHeight = (int) Math.min(normalBounds.height(), shorterLength * MINIMUM_SIZE_PERCENT);
minWidth = (int) (minHeight * aspectRatio);
- maxHeight = (int) Math.max(normalBounds.height(), shorterLength - totalPadding);
+ maxHeight = (int) Math.max(normalBounds.height(), shorterLength - totalVerticalPadding);
maxWidth = (int) (maxHeight * aspectRatio);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 66a4a60..d0998eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import android.graphics.Rect;
+import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -36,8 +37,9 @@
private boolean mIsActive = false;
MainStage(ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue) {
- super(taskOrganizer, displayId, callbacks, syncQueue);
+ StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
+ SurfaceSession surfaceSession) {
+ super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
}
boolean isActive() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 01a81d2..82f95a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.graphics.Rect;
+import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -33,8 +34,9 @@
private static final String TAG = SideStage.class.getSimpleName();
SideStage(ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue) {
- super(taskOrganizer, displayId, callbacks, syncQueue);
+ StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
+ SurfaceSession surfaceSession) {
+ super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
}
void addTask(ActivityManager.RunningTaskInfo task, Rect rootBounds,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index d4506fd..002bfb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
/**
* Interface to engage split-screen feature.
@@ -27,29 +28,6 @@
@ExternalThread
public interface SplitScreen {
/**
- * Stage position isn't specified normally meaning to use what ever it is currently set to.
- */
- int STAGE_POSITION_UNDEFINED = -1;
- /**
- * Specifies that a stage is positioned at the top half of the screen if
- * in portrait mode or at the left half of the screen if in landscape mode.
- */
- int STAGE_POSITION_TOP_OR_LEFT = 0;
-
- /**
- * Specifies that a stage is positioned at the bottom half of the screen if
- * in portrait mode or at the right half of the screen if in landscape mode.
- */
- int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
-
- @IntDef(prefix = { "STAGE_POSITION_" }, value = {
- STAGE_POSITION_UNDEFINED,
- STAGE_POSITION_TOP_OR_LEFT,
- STAGE_POSITION_BOTTOM_OR_RIGHT
- })
- @interface StagePosition {}
-
- /**
* Stage type isn't specified normally meaning to use what ever the default is.
* E.g. exit split-screen and launch the app in fullscreen.
*/
@@ -75,7 +53,7 @@
/** Callback interface for listening to changes in a split-screen stage. */
interface SplitScreenListener {
- void onStagePositionChanged(@StageType int stage, @StagePosition int position);
+ void onStagePositionChanged(@StageType int stage, @SplitPosition int position);
void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 5aa59f2..9a457b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -19,9 +19,9 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -53,6 +53,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.transition.Transitions;
@@ -122,7 +123,7 @@
return mStageCoordinator.isSplitScreenVisible();
}
- public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) {
+ public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task == null) {
throw new IllegalArgumentException("Unknown taskId" + taskId);
@@ -131,7 +132,7 @@
}
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
- @SplitScreen.StagePosition int sideStagePosition) {
+ @SplitPosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
}
@@ -139,7 +140,7 @@
return mStageCoordinator.removeFromSideStage(taskId);
}
- public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
+ public void setSideStagePosition(@SplitPosition int sideStagePosition) {
mStageCoordinator.setSideStagePosition(sideStagePosition);
}
@@ -149,7 +150,7 @@
public void enterSplitScreen(int taskId, boolean leftOrTop) {
moveToSideStage(taskId,
- leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
+ leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
}
public void exitSplitScreen() {
@@ -173,7 +174,7 @@
}
public void startTask(int taskId, @SplitScreen.StageType int stage,
- @SplitScreen.StagePosition int position, @Nullable Bundle options) {
+ @SplitPosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
@@ -184,7 +185,7 @@
}
public void startShortcut(String packageName, String shortcutId,
- @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
+ @SplitScreen.StageType int stage, @SplitPosition int position,
@Nullable Bundle options, UserHandle user) {
options = resolveStartStage(stage, position, options);
@@ -199,7 +200,7 @@
}
public void startIntent(PendingIntent intent, Intent fillInIntent,
- @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
+ @SplitScreen.StageType int stage, @SplitPosition int position,
@Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
@@ -211,11 +212,11 @@
}
private Bundle resolveStartStage(@SplitScreen.StageType int stage,
- @SplitScreen.StagePosition int position, @Nullable Bundle options) {
+ @SplitPosition int position, @Nullable Bundle options) {
switch (stage) {
case STAGE_TYPE_UNDEFINED: {
// Use the stage of the specified position is valid.
- if (position != STAGE_POSITION_UNDEFINED) {
+ if (position != SPLIT_POSITION_UNDEFINED) {
if (position == mStageCoordinator.getSideStagePosition()) {
options = resolveStartStage(STAGE_TYPE_SIDE, position, options);
} else {
@@ -228,7 +229,7 @@
break;
}
case STAGE_TYPE_SIDE: {
- if (position != STAGE_POSITION_UNDEFINED) {
+ if (position != SPLIT_POSITION_UNDEFINED) {
mStageCoordinator.setSideStagePosition(position);
} else {
position = mStageCoordinator.getSideStagePosition();
@@ -240,10 +241,10 @@
break;
}
case STAGE_TYPE_MAIN: {
- if (position != STAGE_POSITION_UNDEFINED) {
+ if (position != SPLIT_POSITION_UNDEFINED) {
// Set the side stage opposite of what we want to the main stage.
- final int sideStagePosition = position == STAGE_POSITION_TOP_OR_LEFT
- ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT;
+ final int sideStagePosition = position == SPLIT_POSITION_TOP_OR_LEFT
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
mStageCoordinator.setSideStagePosition(sideStagePosition);
} else {
position = mStageCoordinator.getMainStagePosition();
@@ -418,7 +419,7 @@
@Override
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,
- @SplitScreen.StagePosition int sidePosition,
+ @SplitPosition int sidePosition,
@Nullable IRemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mController, "startTasks",
(controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 4be9e75..0264c5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -25,8 +25,9 @@
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -47,14 +48,15 @@
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.view.WindowManager;
import android.window.DisplayAreaInfo;
import android.window.IRemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -64,6 +66,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.Transitions;
@@ -84,19 +87,22 @@
* This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
* {@link #onStageHasChildrenChanged(StageListenerImpl).}
*/
-class StageCoordinator implements SplitLayout.LayoutChangeListener,
- RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
+class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+ RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
private static final String TAG = StageCoordinator.class.getSimpleName();
/** internal value for mDismissTop that represents no dismiss */
private static final int NO_DISMISS = -2;
+ private final SurfaceSession mSurfaceSession = new SurfaceSession();
+
private final MainStage mMainStage;
private final StageListenerImpl mMainStageListener = new StageListenerImpl();
private final SideStage mSideStage;
private final StageListenerImpl mSideStageListener = new StageListenerImpl();
- private @SplitScreen.StagePosition int mSideStagePosition = STAGE_POSITION_BOTTOM_OR_RIGHT;
+ @SplitPosition
+ private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
private final int mDisplayId;
private SplitLayout mSplitLayout;
@@ -115,8 +121,8 @@
/** Whether the device is supporting legacy split or not. */
private boolean mUseLegacySplit;
-
@SplitScreen.StageType int mDismissTop = NO_DISMISS;
+
private final Runnable mOnTransitionAnimationComplete = () -> {
// If still playing, let it finish.
if (!isSplitScreenVisible()) {
@@ -137,8 +143,18 @@
mSyncQueue = syncQueue;
mRootTDAOrganizer = rootTDAOrganizer;
mTaskOrganizer = taskOrganizer;
- mMainStage = new MainStage(mTaskOrganizer, mDisplayId, mMainStageListener, mSyncQueue);
- mSideStage = new SideStage(mTaskOrganizer, mDisplayId, mSideStageListener, mSyncQueue);
+ mMainStage = new MainStage(
+ mTaskOrganizer,
+ mDisplayId,
+ mMainStageListener,
+ mSyncQueue,
+ mSurfaceSession);
+ mSideStage = new SideStage(
+ mTaskOrganizer,
+ mDisplayId,
+ mSideStageListener,
+ mSyncQueue,
+ mSurfaceSession);
mDisplayImeController = displayImeController;
mRootTDAOrganizer.registerListener(displayId, this);
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
@@ -176,7 +192,7 @@
}
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
- @SplitScreen.StagePosition int sideStagePosition) {
+ @SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition);
mMainStage.activate(getMainStageBounds(), wct);
@@ -201,7 +217,7 @@
/** Starts 2 tasks in one transition. */
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
- @Nullable Bundle sideOptions, @SplitScreen.StagePosition int sidePosition,
+ @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
@Nullable IRemoteTransition remoteTransition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mainOptions = mainOptions != null ? mainOptions : new Bundle();
@@ -225,20 +241,22 @@
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this);
}
- @SplitScreen.StagePosition int getSideStagePosition() {
+ @SplitLayout.SplitPosition
+ int getSideStagePosition() {
return mSideStagePosition;
}
- @SplitScreen.StagePosition int getMainStagePosition() {
- return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT
- ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT;
+ @SplitLayout.SplitPosition
+ int getMainStagePosition() {
+ return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
}
- void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
+ void setSideStagePosition(@SplitPosition int sideStagePosition) {
setSideStagePosition(sideStagePosition, true /* updateVisibility */);
}
- private void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition,
+ private void setSideStagePosition(@SplitPosition int sideStagePosition,
boolean updateVisibility) {
if (mSideStagePosition == sideStagePosition) return;
mSideStagePosition = sideStagePosition;
@@ -289,7 +307,7 @@
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
}
- void updateActivityOptions(Bundle opts, @SplitScreen.StagePosition int position) {
+ void updateActivityOptions(Bundle opts, @SplitPosition int position) {
addActivityOptions(opts, position == mSideStagePosition ? mSideStage : mMainStage);
if (!mMainStage.isActive()) {
@@ -487,8 +505,8 @@
@Override
public void onSnappedToDismiss(boolean bottomOrRight) {
final boolean mainStageToTop =
- bottomOrRight ? mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT
- : mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT;
+ bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+ : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
if (ENABLE_SHELL_TRANSITIONS) {
onSnappedToDismissTransition(mainStageToTop);
return;
@@ -497,55 +515,49 @@
}
@Override
- public void onBoundsChanging(SplitLayout layout) {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) return;
- final Rect mainStageBounds = getMainStageBounds();
- final Rect sideStageBounds = getSideStageBounds();
-
- mSyncQueue.runInSync(t -> t
- .setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top)
- .setPosition(mMainStage.mRootLeash, mainStageBounds.left, mainStageBounds.top)
- .setPosition(mSideStage.mRootLeash, sideStageBounds.left, sideStageBounds.top)
- // Sets crop to prevent visible region of tasks overlap with each other when
- // re-positioning surfaces while resizing.
- .setWindowCrop(mMainStage.mRootLeash,
- mainStageBounds.width(), mainStageBounds.height())
- .setWindowCrop(mSideStage.mRootLeash,
- sideStageBounds.width(), sideStageBounds.height()));
-
+ public void onDoubleTappedDivider() {
+ setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT);
}
@Override
- public void onDoubleTappedDivider() {
- setSideStagePosition(mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT
- ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT);
+ public void onBoundsChanging(SplitLayout layout) {
+ final StageTaskListener topLeftStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ final StageTaskListener bottomRightStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+
+ mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash,
+ bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer));
}
@Override
public void onBoundsChanged(SplitLayout layout) {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) return;
- final Rect mainStageBounds = getMainStageBounds();
- final Rect sideStageBounds = getSideStageBounds();
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mMainStage.setBounds(mainStageBounds, wct);
- mSideStage.setBounds(sideStageBounds, wct);
- mTaskOrganizer.applyTransaction(wct);
+ final StageTaskListener topLeftStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ final StageTaskListener bottomRightStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
- mSyncQueue.runInSync(t -> t
- // Resets layer of divider bar to make sure it is always on top.
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top)
- .setPosition(mMainStage.mRootLeash,
- mainStageBounds.left, mainStageBounds.top)
- .setPosition(mSideStage.mRootLeash,
- sideStageBounds.left, sideStageBounds.top)
- // Resets crop to apply new surface bounds directly.
- .setWindowCrop(mMainStage.mRootLeash, null)
- .setWindowCrop(mSideStage.mRootLeash, null));
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash,
+ bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer));
+ }
+
+ @Override
+ public int getSplitItemPosition(WindowContainerToken token) {
+ if (token == null) {
+ return SPLIT_POSITION_UNDEFINED;
+ }
+
+ if (token.equals(mMainStage.mRootTaskInfo.getToken())) {
+ return getMainStagePosition();
+ } else if (token.equals(mSideStage.mRootTaskInfo.getToken())) {
+ return getSideStagePosition();
+ }
+
+ return SPLIT_POSITION_UNDEFINED;
}
@Override
@@ -555,7 +567,7 @@
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mDisplayAreaInfo.configuration, this,
b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
- mDisplayImeController);
+ mDisplayImeController, mTaskOrganizer);
}
}
@@ -574,12 +586,12 @@
}
private Rect getSideStageBounds() {
- return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
? mSplitLayout.getBounds1() : mSplitLayout.getBounds2();
}
private Rect getMainStageBounds() {
- return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
}
@@ -742,7 +754,7 @@
// Update local states (before animating).
setDividerVisibility(true);
- setSideStagePosition(STAGE_POSITION_BOTTOM_OR_RIGHT, false /* updateVisibility */);
+ setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateVisibility */);
setSplitsVisible(true);
addDividerBarToTransition(info, t, true /* show */);
@@ -908,6 +920,13 @@
StageCoordinator.this.onStageRootTaskVanished(this);
}
+ @Override
+ public void onNoLongerSupportMultiWindow() {
+ if (mMainStage.isActive()) {
+ StageCoordinator.this.exitSplitScreen();
+ }
+ }
+
private void reset() {
mHasRootTask = false;
mVisible = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 1da0a2d..0fd8eca62 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -29,11 +29,13 @@
import android.graphics.Rect;
import android.util.SparseArray;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SyncTransactionQueue;
import java.io.PrintWriter;
@@ -44,6 +46,7 @@
* They only serve to hold a collection of tasks and provide APIs like
* {@link #setBounds(Rect, WindowContainerTransaction)} for the centralized {@link StageCoordinator}
* to perform operations in-sync with other containers.
+ *
* @see StageCoordinator
*/
class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@@ -58,22 +61,31 @@
/** Callback interface for listening to changes in a split-screen stage. */
public interface StageListenerCallbacks {
void onRootTaskAppeared();
+
void onStatusChanged(boolean visible, boolean hasChildren);
+
void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
+
void onRootTaskVanished();
+ void onNoLongerSupportMultiWindow();
}
+
private final StageListenerCallbacks mCallbacks;
private final SyncTransactionQueue mSyncQueue;
+ private final SurfaceSession mSurfaceSession;
protected ActivityManager.RunningTaskInfo mRootTaskInfo;
protected SurfaceControl mRootLeash;
+ protected SurfaceControl mDimLayer;
protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>();
private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>();
StageTaskListener(ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue) {
+ StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
+ SurfaceSession surfaceSession) {
mCallbacks = callbacks;
mSyncQueue = syncQueue;
+ mSurfaceSession = surfaceSession;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}
@@ -93,6 +105,8 @@
mRootTaskInfo = taskInfo;
mCallbacks.onRootTaskAppeared();
sendStatusChanged();
+ mSyncQueue.runInSync(t -> mDimLayer =
+ SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession));
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
final int taskId = taskInfo.taskId;
mChildrenLeashes.put(taskId, leash);
@@ -113,6 +127,11 @@
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (!taskInfo.supportsMultiWindow) {
+ // Leave split screen if the task no longer supports multi window.
+ mCallbacks.onNoLongerSupportMultiWindow();
+ return;
+ }
if (mRootTaskInfo.taskId == taskInfo.taskId) {
mRootTaskInfo = taskInfo;
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
@@ -140,6 +159,7 @@
final int taskId = taskInfo.taskId;
if (mRootTaskInfo.taskId == taskId) {
mCallbacks.onRootTaskVanished();
+ mSyncQueue.runInSync(t -> t.remove(mDimLayer));
mRootTaskInfo = null;
} else if (mChildrenTaskInfo.contains(taskId)) {
mChildrenTaskInfo.remove(taskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 1f098c2..a646231 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -39,6 +39,7 @@
import android.os.Trace;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.view.View;
import android.window.SplashScreenView;
import com.android.internal.R;
@@ -308,7 +309,7 @@
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
mTmpAttrs.mIconBgColor != Color.TRANSPARENT
? mTmpAttrs.mIconBgColor : mThemeColor,
- iconDrawable, mFinalIconSize, mSplashscreenWorkerHandler);
+ iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
}
private boolean processAdaptiveIcon(Drawable iconDrawable) {
@@ -398,7 +399,17 @@
splashScreenView.setNotCopyable();
splashScreenView.setRevealAnimationSupported(false);
}
- splashScreenView.makeSystemUIColorsTransparent();
+ splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(),
+ splashScreenView.getInitBackgroundColor());
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ });
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return splashScreenView;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 6cbba9f..e8d95ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
@@ -32,7 +31,6 @@
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.Shader;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
@@ -51,59 +49,53 @@
public class SplashscreenIconDrawableFactory {
static Drawable makeIconDrawable(@ColorInt int backgroundColor,
- @NonNull Drawable foregroundDrawable, int iconSize,
+ @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
Handler splashscreenWorkerHandler) {
if (foregroundDrawable instanceof Animatable) {
return new AnimatableIconDrawable(backgroundColor, foregroundDrawable);
} else if (foregroundDrawable instanceof AdaptiveIconDrawable) {
- return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable, iconSize,
- splashscreenWorkerHandler);
+ return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable,
+ srcIconSize, iconSize, splashscreenWorkerHandler);
} else {
// TODO for legacy icon don't use adaptive icon drawable to wrapper it
return new ImmobileIconDrawable(new AdaptiveIconDrawable(
- new ColorDrawable(backgroundColor), foregroundDrawable), iconSize,
- splashscreenWorkerHandler);
+ new ColorDrawable(backgroundColor), foregroundDrawable),
+ srcIconSize, iconSize, splashscreenWorkerHandler);
}
}
private static class ImmobileIconDrawable extends Drawable {
- private boolean mCacheComplete;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
| Paint.FILTER_BITMAP_FLAG);
+ private final Matrix mMatrix = new Matrix();
+ private Bitmap mIconBitmap;
- ImmobileIconDrawable(AdaptiveIconDrawable drawable, int iconSize,
+ ImmobileIconDrawable(AdaptiveIconDrawable drawable, int srcIconSize, int iconSize,
Handler splashscreenWorkerHandler) {
- splashscreenWorkerHandler.post(() -> cachePaint(drawable, iconSize, iconSize));
+ final float scale = (float) iconSize / srcIconSize;
+ mMatrix.setScale(scale, scale);
+ splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
}
- private void cachePaint(AdaptiveIconDrawable drawable, int width, int height) {
+ private void preDrawIcon(AdaptiveIconDrawable drawable, int size) {
synchronized (mPaint) {
- if (mCacheComplete) {
- return;
- }
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cachePaint");
- final Bitmap layersBitmap = Bitmap.createBitmap(width, height,
- Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(layersBitmap);
- drawable.setBounds(0, 0, width, height);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "preDrawIcon");
+ mIconBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(mIconBitmap);
+ drawable.setBounds(0, 0, size, size);
drawable.draw(canvas);
- final Shader layersShader = new BitmapShader(layersBitmap, Shader.TileMode.CLAMP,
- Shader.TileMode.CLAMP);
- mPaint.setShader(layersShader);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- mCacheComplete = true;
}
}
@Override
public void draw(Canvas canvas) {
synchronized (mPaint) {
- if (mCacheComplete) {
- final Rect bounds = getBounds();
- canvas.drawRect(bounds, mPaint);
+ if (mIconBitmap != null) {
+ canvas.drawBitmap(mIconBitmap, mMatrix, mPaint);
} else {
// this shouldn't happen, but if it really happen, invalidate self to wait
- // for cachePaint finish.
+ // for bitmap to be ready.
invalidateSelf();
}
}
@@ -111,12 +103,10 @@
@Override
public void setAlpha(int alpha) {
-
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
-
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 26e8753..187e104 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -25,12 +25,10 @@
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -43,13 +41,13 @@
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
+import android.widget.FrameLayout;
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
import com.android.internal.R;
-import com.android.internal.policy.PhoneWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -152,14 +150,6 @@
return;
}
- CharSequence nonLocalizedLabel = activityInfo.nonLocalizedLabel;
- int labelRes = activityInfo.labelRes;
- if (activityInfo.nonLocalizedLabel == null && activityInfo.labelRes == 0) {
- ApplicationInfo app = activityInfo.applicationInfo;
- nonLocalizedLabel = app.nonLocalizedLabel;
- labelRes = app.labelRes;
- }
-
final int taskId = taskInfo.taskId;
Context context = mContext;
// replace with the default theme if the application didn't set
@@ -169,8 +159,7 @@
: com.android.internal.R.style.Theme_DeviceDefault_DayNight;
if (DEBUG_SPLASH_SCREEN) {
Slog.d(TAG, "addSplashScreen " + activityInfo.packageName
- + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
- + Integer.toHexString(theme) + " task= " + taskInfo.taskId);
+ + " theme=" + Integer.toHexString(theme) + " task= " + taskInfo.taskId);
}
// Obtain proper context to launch on the right display.
@@ -180,7 +169,7 @@
return;
}
context = displayContext;
- if (theme != context.getThemeResId() || labelRes != 0) {
+ if (theme != context.getThemeResId()) {
try {
context = context.createPackageContextAsUser(activityInfo.packageName,
CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
@@ -222,23 +211,22 @@
typedArray.recycle();
}
- final PhoneWindow win = new PhoneWindow(context);
- win.setIsStartingWindow(true);
-
- final Resources res = context.getResources();
- final CharSequence label = res.getText(labelRes, null);
- // Only change the accessibility title if the label is localized
- if (label != null) {
- win.setTitle(label, true);
- } else {
- win.setTitle(nonLocalizedLabel, false);
- }
-
- int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+ params.setFitInsetsSides(0);
+ params.setFitInsetsTypes(0);
+ int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
+ params.layoutInDisplayCutoutMode = a.getInt(
+ R.styleable.Window_windowLayoutInDisplayCutoutMode,
+ params.layoutInDisplayCutoutMode);
+ params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
a.recycle();
// Assumes it's safe to show starting windows of launched apps while
@@ -256,28 +244,15 @@
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- win.setFlags(windowFlags, windowFlags);
-
- final int iconRes = activityInfo.getIconResource();
- final int logoRes = activityInfo.getLogoResource();
- win.setDefaultIcon(iconRes);
- win.setDefaultLogo(logoRes);
-
- final WindowManager.LayoutParams params = win.getAttributes();
- params.type = WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
- params.width = WindowManager.LayoutParams.MATCH_PARENT;
- params.height = WindowManager.LayoutParams.MATCH_PARENT;
+ params.flags = windowFlags;
params.token = appToken;
params.packageName = activityInfo.packageName;
- params.windowAnimations = win.getWindowStyle().getResourceId(
- com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
// Setting as trusted overlay to let touches pass through. This is safe because this
// window is controlled by the system.
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
- params.format = PixelFormat.RGBA_8888;
- if (!res.getCompatibilityInfo().supportsScreen()) {
+ if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
@@ -297,6 +272,7 @@
// Record whether create splash screen view success, notify to current thread after
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
+ final FrameLayout rootLayout = new FrameLayout(context);
final Runnable setViewSynchronized = () -> {
// waiting for setContentView before relayoutWindow
SplashScreenView contentView = viewSupplier.get();
@@ -306,8 +282,7 @@
// if view == null then creation of content view was failed.
if (contentView != null) {
try {
- win.setContentView(contentView);
- contentView.cacheRootWindow(win);
+ rootLayout.addView(contentView);
} catch (RuntimeException e) {
Slog.w(TAG, "failed set content view to starting window "
+ "at taskId: " + taskId, e);
@@ -321,9 +296,8 @@
viewSupplier::setView);
try {
- final View view = win.getDecorView();
final WindowManager wm = context.getSystemService(WindowManager.class);
- postAddWindow(taskId, appToken, view, wm, params);
+ postAddWindow(taskId, appToken, rootLayout, wm, params);
// We use the splash screen worker thread to create SplashScreenView while adding the
// window, as otherwise Choreographer#doFrame might be delayed on this thread.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
index d21183e..e73d9aa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -18,9 +18,12 @@
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -43,7 +46,11 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-/** Tests for {@link AppPair} */
+/**
+ * Tests for {@link AppPair}
+ * Build/Install/Run:
+ * atest WMShellUnitTests:AppPairTests
+ */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class AppPairTests extends ShellTestCase {
@@ -63,6 +70,7 @@
mTaskOrganizer,
mSyncQueue,
mDisplayController);
+ spyOn(mController);
}
@After
@@ -97,4 +105,19 @@
assertThat(pair.contains(task1.taskId)).isFalse();
assertThat(pair.contains(task2.taskId)).isFalse();
}
+
+ @Test
+ @UiThreadTest
+ public void testOnTaskInfoChanged_notSupportsMultiWindow() {
+ final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
+ final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
+
+ final AppPair pair = mController.pairInner(task1, task2);
+ assertThat(pair.contains(task1.taskId)).isTrue();
+ assertThat(pair.contains(task2.taskId)).isTrue();
+
+ task1.supportsMultiWindow = false;
+ pair.onTaskInfoChanged(task1);
+ verify(mController).unpair(pair.getRootTaskId());
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 7b0e6b9..952dc31 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -35,6 +35,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayImeController;
@@ -48,9 +49,10 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SplitLayoutTests extends ShellTestCase {
- @Mock SplitLayout.LayoutChangeListener mLayoutChangeListener;
+ @Mock SplitLayout.SplitLayoutHandler mSplitLayoutHandler;
@Mock SurfaceControl mRootLeash;
@Mock DisplayImeController mDisplayImeController;
+ @Mock ShellTaskOrganizer mTaskOrganizer;
private SplitLayout mSplitLayout;
@Before
@@ -60,9 +62,10 @@
"TestSplitLayout",
mContext,
getConfiguration(false),
- mLayoutChangeListener,
+ mSplitLayoutHandler,
b -> b.setParent(mRootLeash),
- mDisplayImeController);
+ mDisplayImeController,
+ mTaskOrganizer);
}
@Test
@@ -76,19 +79,19 @@
@Test
public void testUpdateDivideBounds() {
mSplitLayout.updateDivideBounds(anyInt());
- verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onBoundsChanging(any(SplitLayout.class));
}
@Test
public void testSetDividePosition() {
mSplitLayout.setDividePosition(anyInt());
- verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onBoundsChanged(any(SplitLayout.class));
}
@Test
public void testOnDoubleTappedDivider() {
mSplitLayout.onDoubleTappedDivider();
- verify(mLayoutChangeListener).onDoubleTappedDivider();
+ verify(mSplitLayoutHandler).onDoubleTappedDivider();
}
@Test
@@ -98,11 +101,11 @@
DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
- verify(mLayoutChangeListener).onSnappedToDismiss(eq(false));
+ verify(mSplitLayoutHandler).onSnappedToDismiss(eq(false));
snapTarget = getSnapTarget(0 /* position */,
DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
- verify(mLayoutChangeListener).onSnappedToDismiss(eq(true));
+ verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true));
}
private static Configuration getConfiguration(boolean isLandscape) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 86d0d82..698315a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -29,7 +29,6 @@
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
import org.junit.Test;
@@ -43,7 +42,6 @@
public class SplitWindowManagerTests extends ShellTestCase {
@Mock SurfaceControl mSurfaceControl;
@Mock SplitLayout mSplitLayout;
- @Mock DisplayImeController mDisplayImeController;
private SplitWindowManager mSplitWindowManager;
@Before
@@ -52,7 +50,7 @@
final Configuration configuration = new Configuration();
configuration.setToDefaults();
mSplitWindowManager = new SplitWindowManager("TestSplitDivider", mContext, configuration,
- b -> b.setParent(mSurfaceControl), mDisplayImeController);
+ b -> b.setParent(mSurfaceControl));
when(mSplitLayout.getDividerBounds()).thenReturn(
new Rect(0, 0, configuration.windowConfiguration.getBounds().width(),
configuration.windowConfiguration.getBounds().height()));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 2f2bbba..ba73d55 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -24,13 +24,13 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -206,7 +206,7 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
}
@Test
@@ -218,12 +218,12 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -235,12 +235,12 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -252,7 +252,7 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
}
@Test
@@ -264,7 +264,7 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
}
@Test
@@ -277,13 +277,13 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -296,13 +296,13 @@
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
+ eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
+ eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 25d90b3..1852279 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -398,4 +398,14 @@
verify(mSpiedOneHandedController, never()).startOneHanded();
verify(mSpiedOneHandedController, never()).stopOneHanded();
}
+
+ @Test
+ public void testControllerInit_tutorialAddStateChangeListener() {
+ when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(true);
+ when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+ when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+ when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
+
+ verify(mSpiedTransitionState).addSListeners(mMockTutorialHandler);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 5f2bfad..1bc2a08 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -16,19 +16,26 @@
package com.android.wm.shell.onehanded;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+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.om.IOverlayManager;
-import android.os.Handler;
import android.testing.AndroidTestingRunner;
-import android.util.ArrayMap;
+import android.view.Display;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.Before;
import org.junit.Test;
@@ -39,62 +46,94 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
+ Display mDisplay;
+ DisplayLayout mDisplayLayout;
OneHandedTimeoutHandler mTimeoutHandler;
- OneHandedController mOneHandedController;
OneHandedState mSpiedTransitionState;
+ OneHandedTutorialHandler mSpiedTutorialHandler;
@Mock
- OneHandedTouchHandler mMockTouchHandler;
- @Mock
- OneHandedTutorialHandler mMockTutorialHandler;
- @Mock
- DisplayController mMockDisplayController;
- @Mock
- OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
- @Mock
- OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
- @Mock
- IOverlayManager mMockOverlayManager;
- @Mock
- TaskStackListenerImpl mMockTaskStackListener;
- @Mock
ShellExecutor mMockShellMainExecutor;
@Mock
- Handler mMockShellMainHandler;
- @Mock
- OneHandedUiEventLogger mMockUiEventLogger;
- @Mock
OneHandedSettingsUtil mMockSettingsUtil;
@Mock
- OneHandedAccessibilityUtil mMockAccessibilityUtil;
+ WindowManager mMockWindowManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor);
- mSpiedTransitionState = new OneHandedState();
+ when(mMockSettingsUtil.getTutorialShownCounts(any(), anyInt())).thenReturn(0);
- when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
- mOneHandedController = new OneHandedController(
- mContext,
- mMockDisplayController,
- mMockBackgroundOrganizer,
- mMockDisplayAreaOrganizer,
- mMockTouchHandler,
- mMockTutorialHandler,
- mMockSettingsUtil,
- mMockAccessibilityUtil,
- mTimeoutHandler,
- mSpiedTransitionState,
- mMockUiEventLogger,
- mMockOverlayManager,
- mMockTaskStackListener,
- mMockShellMainExecutor,
- mMockShellMainHandler);
+ mDisplay = mContext.getDisplay();
+ mDisplayLayout = new DisplayLayout(mContext, mDisplay);
+ mSpiedTransitionState = spy(new OneHandedState());
+ mSpiedTutorialHandler = spy(
+ new OneHandedTutorialHandler(mContext, mDisplayLayout, mMockWindowManager,
+ mMockSettingsUtil, mMockShellMainExecutor));
+ mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor);
}
@Test
- public void testRegisterForDisplayAreaOrganizer() {
- verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mMockTutorialHandler);
+ public void testDefaultZeroShownCounts_canShowTutorial() {
+ assertThat(mSpiedTutorialHandler.canShowTutorial()).isTrue();
+ verify(mMockShellMainExecutor, never()).execute(any());
+ }
+
+ @Test
+ public void testDefaultZeroShownCounts_doNotAttachWindow() {
+ verify(mMockShellMainExecutor, never()).execute(any());
+ }
+
+ @Test
+ public void testOnStateChangedEntering_createViewAndAttachToWindow() {
+ when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true);
+ try {
+ mSpiedTutorialHandler.onStateChanged(STATE_ENTERING);
+ } catch (ClassCastException e) {
+ // no-op, just assert createViewAndAttachToWindow() to be called
+ }
+
+ verify(mSpiedTutorialHandler).createViewAndAttachToWindow(any());
+ }
+
+ @Test
+ public void testOnStateChangedNone_removeViewAndAttachToWindow() {
+ when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true);
+ try {
+ mSpiedTutorialHandler.onStateChanged(STATE_NONE);
+ } catch (ClassCastException e) {
+ // no-op, just assert removeTutorialFromWindowManager() to be called
+ }
+
+ verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(true);
+ }
+
+ @Test
+ public void testOnStateChangedNone_shouldNotAttachWindow() {
+ when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true);
+ try {
+ mSpiedTutorialHandler.onStateChanged(STATE_NONE);
+ } catch (ClassCastException e) {
+ // no-op, just assert setTutorialShownCountIncrement() never be called
+ }
+
+ verify(mSpiedTutorialHandler, never()).setTutorialShownCountIncrement();
+ }
+
+ @Test
+ public void testOnConfigurationChanged_shouldUpdateViewContent() {
+ when(mSpiedTutorialHandler.canShowTutorial()).thenReturn(true);
+ try {
+ mSpiedTutorialHandler.onStateChanged(STATE_ENTERING);
+ } catch (ClassCastException e) {
+ // no-op, set current state for test onConfigurationChanged()
+ }
+ try {
+ mSpiedTutorialHandler.onConfigurationChanged();
+ } catch (ClassCastException e) {
+ // no-op, just assert removeTutorialFromWindowManager() be called
+ }
+
+ verify(mSpiedTutorialHandler).removeTutorialFromWindowManager(false);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
index 702e894..1bb5fd1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
@@ -22,6 +22,7 @@
import android.app.ActivityManager;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,7 +37,6 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
/** Tests for {@link MainStage} */
@SmallTest
@@ -47,14 +47,16 @@
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ActivityManager.RunningTaskInfo mRootTaskInfo;
@Mock private SurfaceControl mRootLeash;
- @Spy private WindowContainerTransaction mWct;
+ private WindowContainerTransaction mWct = new WindowContainerTransaction();
+ private SurfaceSession mSurfaceSession = new SurfaceSession();
private MainStage mMainStage;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
- mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue);
+ mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue,
+ mSurfaceSession);
mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
index 01888b7..56a0056 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -52,13 +53,15 @@
@Mock private ActivityManager.RunningTaskInfo mRootTask;
@Mock private SurfaceControl mRootLeash;
@Spy private WindowContainerTransaction mWct;
+ private SurfaceSession mSurfaceSession = new SurfaceSession();
private SideStage mSideStage;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mRootTask = new TestRunningTaskInfoBuilder().build();
- mSideStage = new SideStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue);
+ mSideStage = new SideStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue,
+ mSurfaceSession);
mSideStage.onTaskAppeared(mRootTask, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 08ac2a6..aca80f3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -43,6 +43,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
@@ -80,6 +81,7 @@
@Mock private DisplayImeController mDisplayImeController;
@Mock private TransactionPool mTransactionPool;
@Mock private Transitions mTransitions;
+ @Mock private SurfaceSession mSurfaceSession;
private SplitLayout mSplitLayout;
private MainStage mMainStage;
private SideStage mSideStage;
@@ -98,10 +100,10 @@
doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire();
mSplitLayout = SplitTestUtils.createMockSplitLayout();
mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mock(
- StageTaskListener.StageListenerCallbacks.class), mSyncQueue);
+ StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = new SideStage(mTaskOrganizer, DEFAULT_DISPLAY, mock(
- StageTaskListener.StageListenerCallbacks.class), mSyncQueue);
+ StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 924e946..06b0868 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -18,7 +18,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -73,7 +73,7 @@
public void testMoveToSideStage() {
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
- mStageCoordinator.moveToSideStage(task, STAGE_POSITION_BOTTOM_OR_RIGHT);
+ mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT);
verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class));
verify(mSideStage).addTask(eq(task), any(Rect.class),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index c66e073..90b5b37 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -27,6 +27,7 @@
import android.app.ActivityManager;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -38,16 +39,24 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-/** Tests for {@link StageTaskListener} */
+/**
+ * Tests for {@link StageTaskListener}
+ * Build/Install/Run:
+ * atest WMShellUnitTests:StageTaskListenerTests
+ */
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class StageTaskListenerTests {
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private StageTaskListener.StageListenerCallbacks mCallbacks;
@Mock private SyncTransactionQueue mSyncQueue;
+ @Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
+ private SurfaceSession mSurfaceSession = new SurfaceSession();
private ActivityManager.RunningTaskInfo mRootTask;
private StageTaskListener mStageTaskListener;
@@ -58,13 +67,24 @@
mTaskOrganizer,
DEFAULT_DISPLAY,
mCallbacks,
- mSyncQueue);
+ mSyncQueue,
+ mSurfaceSession);
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID;
mStageTaskListener.onTaskAppeared(mRootTask, new SurfaceControl());
}
@Test
+ public void testInitsDimLayer() {
+ verify(mSyncQueue).runInSync(mRunnableCaptor.capture());
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mRunnableCaptor.getValue().runWithTransaction(t);
+ t.apply();
+
+ assertThat(mStageTaskListener.mDimLayer).isNotNull();
+ }
+
+ @Test
public void testRootTaskAppeared() {
assertThat(mStageTaskListener.mRootTaskInfo.taskId).isEqualTo(mRootTask.taskId);
verify(mCallbacks).onRootTaskAppeared();
@@ -101,4 +121,14 @@
mStageTaskListener.onTaskVanished(mRootTask);
verify(mCallbacks).onRootTaskVanished();
}
+
+ @Test
+ public void testTaskInfoChanged_notSupportsMultiWindow() {
+ final ActivityManager.RunningTaskInfo childTask =
+ new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build();
+ childTask.supportsMultiWindow = false;
+
+ mStageTaskListener.onTaskInfoChanged(childTask);
+ verify(mCallbacks).onNoLongerSupportMultiWindow();
+ }
}
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 0599bfa..807fb75 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -94,13 +94,14 @@
float uStretchAffectedDist,
float uInverseStretchAffectedDist,
float distanceStretched,
- float interpolationStrength
+ float interpolationStrength,
+ float viewportDimension
) {
float offsetPos = inPos - reverseStretchDist;
float posBasedVariation = mix(
1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
float stretchIntensity = (-overscroll) * posBasedVariation;
- return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
+ return viewportDimension - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
}
// Prefer usage of return values over out parameters as it enables
@@ -113,54 +114,51 @@
float uInverseStretchAffectedDist,
float distanceStretched,
float distanceDiff,
- float interpolationStrength
+ float interpolationStrength,
+ float viewportDimension
) {
- float outPos = inPos;
if (overscroll > 0) {
- if (inPos <= uStretchAffectedDist) {
- outPos = computeOverscrollStart(
- inPos,
- overscroll,
- uStretchAffectedDist,
- uInverseStretchAffectedDist,
- distanceStretched,
- interpolationStrength
- );
- } else if (inPos >= distanceStretched) {
- outPos = distanceDiff + inPos;
- }
+ if (inPos <= uStretchAffectedDist) {
+ return computeOverscrollStart(
+ inPos,
+ overscroll,
+ uStretchAffectedDist,
+ uInverseStretchAffectedDist,
+ distanceStretched,
+ interpolationStrength
+ );
+ } else {
+ return distanceDiff + inPos;
}
- if (overscroll < 0) {
- float stretchAffectedDist = 1. - uStretchAffectedDist;
- if (inPos >= stretchAffectedDist) {
- outPos = computeOverscrollEnd(
- inPos,
- overscroll,
- stretchAffectedDist,
- uStretchAffectedDist,
- uInverseStretchAffectedDist,
- distanceStretched,
- interpolationStrength
- );
- } else if (inPos < stretchAffectedDist) {
- outPos = -distanceDiff + inPos;
- }
+ } else if (overscroll < 0) {
+ float stretchAffectedDist = viewportDimension - uStretchAffectedDist;
+ if (inPos >= stretchAffectedDist) {
+ return computeOverscrollEnd(
+ inPos,
+ overscroll,
+ stretchAffectedDist,
+ uStretchAffectedDist,
+ uInverseStretchAffectedDist,
+ distanceStretched,
+ interpolationStrength,
+ viewportDimension
+ );
+ } else {
+ return -distanceDiff + inPos;
}
- return outPos;
+ } else {
+ return inPos;
+ }
}
vec4 main(vec2 coord) {
- // Normalize SKSL pixel coordinate into a unit vector
- float inU = coord.x / viewportWidth;
- float inV = coord.y / viewportHeight;
+ float inU = coord.x;
+ float inV = coord.y;
float outU;
float outV;
- float stretchIntensity;
- // Add the normalized scroll position within scrolling list
+
inU += uScrollX;
inV += uScrollY;
- outU = inU;
- outV = inV;
outU = computeOverscroll(
inU,
uOverscrollX,
@@ -168,7 +166,8 @@
uInverseDistanceStretchedX,
uDistanceStretchedX,
uDistDiffX,
- uInterpolationStrength
+ uInterpolationStrength,
+ viewportWidth
);
outV = computeOverscroll(
inV,
@@ -177,15 +176,15 @@
uInverseDistanceStretchedY,
uDistanceStretchedY,
uDistDiffY,
- uInterpolationStrength
+ uInterpolationStrength,
+ viewportHeight
);
- coord.x = outU * viewportWidth;
- coord.y = outV * viewportHeight;
+ coord.x = outU;
+ coord.y = outV;
return sample(uContentTexture, coord);
})");
static const float ZERO = 0.f;
-static const float CONTENT_DISTANCE_STRETCHED = 1.f;
static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
sk_sp<SkShader> StretchEffect::getShader(float width, float height,
@@ -196,12 +195,12 @@
float normOverScrollDistX = mStretchDirection.x();
float normOverScrollDistY = mStretchDirection.y();
- float distanceStretchedX = CONTENT_DISTANCE_STRETCHED / (1 + abs(normOverScrollDistX));
- float distanceStretchedY = CONTENT_DISTANCE_STRETCHED / (1 + abs(normOverScrollDistY));
- float inverseDistanceStretchedX = 1.f / CONTENT_DISTANCE_STRETCHED;
- float inverseDistanceStretchedY = 1.f / CONTENT_DISTANCE_STRETCHED;
- float diffX = distanceStretchedX - CONTENT_DISTANCE_STRETCHED;
- float diffY = distanceStretchedY - CONTENT_DISTANCE_STRETCHED;
+ float distanceStretchedX = width / (1 + abs(normOverScrollDistX));
+ float distanceStretchedY = height / (1 + abs(normOverScrollDistY));
+ float inverseDistanceStretchedX = 1.f / width;
+ float inverseDistanceStretchedY = 1.f / height;
+ float diffX = distanceStretchedX - width;
+ float diffY = distanceStretchedY - height;
if (mBuilder == nullptr) {
mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
@@ -210,8 +209,8 @@
mBuilder->child("uContentTexture") = snapshotImage->makeShader(
SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
- mBuilder->uniform("uStretchAffectedDistX").set(&CONTENT_DISTANCE_STRETCHED, 1);
- mBuilder->uniform("uStretchAffectedDistY").set(&CONTENT_DISTANCE_STRETCHED, 1);
+ mBuilder->uniform("uStretchAffectedDistX").set(&width, 1);
+ mBuilder->uniform("uStretchAffectedDistY").set(&height, 1);
mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1);
mBuilder->uniform("uInverseDistanceStretchedX").set(&inverseDistanceStretchedX, 1);
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 10889e7..d173782 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -77,6 +77,7 @@
setUniform(effectBuilder, "in_radius", params.radius);
setUniform(effectBuilder, "in_progress", params.progress);
setUniform(effectBuilder, "in_turbulencePhase", params.turbulencePhase);
+ setUniform(effectBuilder, "in_noisePhase", params.turbulencePhase->value * 0.001);
SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform("in_color");
if (uniform.fVar != nullptr) {
@@ -120,17 +121,24 @@
static constexpr float PI_ROTATE_LEFT = PI * -0.0078125;
static constexpr float SCALE = 1.5;
- static void setUniform(SkRuntimeShaderBuilder& effectBuilder, std::string name,
+ static void setUniform(SkRuntimeShaderBuilder& effectBuilder, const char* name,
sp<uirenderer::CanvasPropertyPrimitive> property) {
- SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name);
if (uniform.fVar != nullptr) {
uniform = property->value;
}
}
- static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, std::string name, float a,
+ static void setUniform(SkRuntimeShaderBuilder& effectBuilder, const char* name, float value) {
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name);
+ if (uniform.fVar != nullptr) {
+ uniform = value;
+ }
+ }
+
+ static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, const char* name, float a,
float b) {
- SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name);
if (uniform.fVar != nullptr) {
uniform = SkV2{a, b};
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 0112686..07146e8 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -340,6 +340,8 @@
}
void VulkanManager::initialize() {
+ std::lock_guard _lock{mInitializeLock};
+
if (mDevice != VK_NULL_HANDLE) {
return;
}
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 7b5fe19..b816649 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -220,6 +220,8 @@
VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
void* mDestroySemaphoreContext = nullptr;
+
+ std::mutex mInitializeLock;
};
} /* namespace renderthread */
diff --git a/location/java/android/location/SatellitePvt.java b/location/java/android/location/SatellitePvt.java
index 1456f74..bb9ae6e 100644
--- a/location/java/android/location/SatellitePvt.java
+++ b/location/java/android/location/SatellitePvt.java
@@ -45,8 +45,41 @@
*/
@SystemApi
public final class SatellitePvt implements Parcelable {
+ /**
+ * Bit mask for {@link #mFlags} indicating valid satellite position, velocity and clock info
+ * fields are stored in the SatellitePvt.
+ */
+ private static final int HAS_POSITION_VELOCITY_CLOCK_INFO = 1 << 0;
+
+ /**
+ * Bit mask for {@link #mFlags} indicating a valid iono delay field is stored in the
+ * SatellitePvt.
+ */
+ private static final int HAS_IONO = 1 << 1;
+
+ /**
+ * Bit mask for {@link #mFlags} indicating a valid tropo delay field is stored in the
+ * SatellitePvt.
+ */
+ private static final int HAS_TROPO = 1 << 2;
+
+ /**
+ * A bitfield of flags indicating the validity of the fields in this SatellitePvt.
+ * The bit masks are defined in the constants with prefix HAS_*
+ *
+ * <p>Fields for which there is no corresponding flag must be filled in with a valid value.
+ * For convenience, these are marked as mandatory.
+ *
+ * <p>Others fields may have invalid information in them, if not marked as valid by the
+ * corresponding bit in flags.
+ */
+ private final int mFlags;
+
+ @Nullable
private final PositionEcef mPositionEcef;
+ @Nullable
private final VelocityEcef mVelocityEcef;
+ @Nullable
private final ClockInfo mClockInfo;
private final double mIonoDelayMeters;
private final double mTropoDelayMeters;
@@ -351,20 +384,13 @@
}
private SatellitePvt(
- @NonNull PositionEcef positionEcef,
- @NonNull VelocityEcef velocityEcef,
- @NonNull ClockInfo clockInfo,
+ int flags,
+ @Nullable PositionEcef positionEcef,
+ @Nullable VelocityEcef velocityEcef,
+ @Nullable ClockInfo clockInfo,
double ionoDelayMeters,
double tropoDelayMeters) {
- if (positionEcef == null) {
- throw new IllegalArgumentException("Position Ecef cannot be null.");
- }
- if (velocityEcef == null) {
- throw new IllegalArgumentException("Velocity Ecef cannot be null.");
- }
- if (clockInfo == null) {
- throw new IllegalArgumentException("Clock Info cannot be null.");
- }
+ mFlags = flags;
mPositionEcef = positionEcef;
mVelocityEcef = velocityEcef;
mClockInfo = clockInfo;
@@ -373,10 +399,17 @@
}
/**
+ * Gets a bitmask of fields present in this object
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
* Returns a {@link PositionEcef} object that contains estimates of the satellite
* position fields in ECEF coordinate frame.
*/
- @NonNull
+ @Nullable
public PositionEcef getPositionEcef() {
return mPositionEcef;
}
@@ -385,7 +418,7 @@
* Returns a {@link VelocityEcef} object that contains estimates of the satellite
* velocity fields in the ECEF coordinate frame.
*/
- @NonNull
+ @Nullable
public VelocityEcef getVelocityEcef() {
return mVelocityEcef;
}
@@ -394,7 +427,7 @@
* Returns a {@link ClockInfo} object that contains estimates of the satellite
* clock info.
*/
- @NonNull
+ @Nullable
public ClockInfo getClockInfo() {
return mClockInfo;
}
@@ -415,11 +448,29 @@
return mTropoDelayMeters;
}
+ /** Returns {@code true} if {@link #getPositionEcef()}, {@link #getVelocityEcef()},
+ * and {@link #getClockInfo()} are valid.
+ */
+ public boolean hasPositionVelocityClockInfo() {
+ return (mFlags & HAS_POSITION_VELOCITY_CLOCK_INFO) != 0;
+ }
+
+ /** Returns {@code true} if {@link #getIonoDelayMeters()} is valid. */
+ public boolean hasIono() {
+ return (mFlags & HAS_IONO) != 0;
+ }
+
+ /** Returns {@code true} if {@link #getTropoDelayMeters()} is valid. */
+ public boolean hasTropo() {
+ return (mFlags & HAS_TROPO) != 0;
+ }
+
public static final @android.annotation.NonNull Creator<SatellitePvt> CREATOR =
new Creator<SatellitePvt>() {
@Override
@Nullable
public SatellitePvt createFromParcel(Parcel in) {
+ int flags = in.readInt();
ClassLoader classLoader = getClass().getClassLoader();
PositionEcef positionEcef = in.readParcelable(classLoader);
VelocityEcef velocityEcef = in.readParcelable(classLoader);
@@ -428,6 +479,7 @@
double tropoDelayMeters = in.readDouble();
return new SatellitePvt(
+ flags,
positionEcef,
velocityEcef,
clockInfo,
@@ -448,6 +500,7 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeInt(mFlags);
parcel.writeParcelable(mPositionEcef, flags);
parcel.writeParcelable(mVelocityEcef, flags);
parcel.writeParcelable(mClockInfo, flags);
@@ -458,7 +511,8 @@
@Override
public String toString() {
return "SatellitePvt{"
- + "PositionEcef=" + mPositionEcef
+ + "Flags=" + mFlags
+ + ", PositionEcef=" + mPositionEcef
+ ", VelocityEcef=" + mVelocityEcef
+ ", ClockInfo=" + mClockInfo
+ ", IonoDelayMeters=" + mIonoDelayMeters
@@ -470,13 +524,30 @@
* Builder class for SatellitePvt.
*/
public static final class Builder {
- private PositionEcef mPositionEcef;
- private VelocityEcef mVelocityEcef;
- private ClockInfo mClockInfo;
+ /**
+ * For documentation of below fields, see corresponding fields in {@link
+ * SatellitePvt}.
+ */
+ private int mFlags;
+ @Nullable private PositionEcef mPositionEcef;
+ @Nullable private VelocityEcef mVelocityEcef;
+ @Nullable private ClockInfo mClockInfo;
private double mIonoDelayMeters;
private double mTropoDelayMeters;
/**
+ * Sets a bitmask of fields present in this object
+ *
+ * @param flags int flags
+ * @return Builder builder object
+ */
+ @NonNull
+ public Builder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ /**
* Set position ECEF.
*
* @param positionEcef position ECEF object
@@ -546,7 +617,7 @@
*/
@NonNull
public SatellitePvt build() {
- return new SatellitePvt(mPositionEcef, mVelocityEcef, mClockInfo,
+ return new SatellitePvt(mFlags, mPositionEcef, mVelocityEcef, mClockInfo,
mIonoDelayMeters, mTropoDelayMeters);
}
}
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index a75792c..6eb8348 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -59,6 +59,22 @@
],
}
+java_library {
+ name: "framework-connectivity-annotations",
+ sdk_version: "module_current",
+ srcs: [
+ "src/android/net/ConnectivityAnnotations.java",
+ ],
+ libs: [
+ "framework-annotations-lib",
+ "framework-connectivity",
+ ],
+ visibility: [
+ "//frameworks/base:__subpackages__",
+ "//packages/modules/Connectivity:__subpackages__",
+ ],
+}
+
java_sdk_library {
name: "framework-connectivity",
sdk_version: "module_current",
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index 13ecb12..33f4d14 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -70,7 +70,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
method @Deprecated public boolean getBackgroundDataSetting();
method @Nullable public android.net.Network getBoundNetworkForProcess();
method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
@@ -406,6 +406,7 @@
method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
+ method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
}
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index b219375..6c454bc 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -48,6 +48,7 @@
public class ConnectivitySettingsManager {
method public static void clearGlobalProxy(@NonNull android.content.Context);
+ method @NonNull public static java.util.Set<java.lang.String> getAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@@ -65,9 +66,9 @@
method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
method public static int getPrivateDnsMode(@NonNull android.content.Context);
- method @NonNull public static java.util.Set<java.lang.String> getRestrictedAllowedApps(@NonNull android.content.Context);
method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@@ -85,7 +86,6 @@
method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
- method public static void setRestrictedAllowedApps(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 52673c9..d1d51da 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -296,7 +296,6 @@
method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
method @NonNull public android.net.NetworkCapabilities build();
- method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
@@ -310,6 +309,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
+ method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
}
public class NetworkProvider {
@@ -398,6 +398,7 @@
public abstract class QosFilter {
method @NonNull public abstract android.net.Network getNetwork();
method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+ method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int);
}
public final class QosSession implements android.os.Parcelable {
@@ -420,6 +421,7 @@
method public int describeContents();
method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
method @NonNull public android.net.Network getNetwork();
+ method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
new file mode 100644
index 0000000..eb1faa0
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
@@ -0,0 +1,51 @@
+/*
+ * 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.net;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Type annotations for constants used in the connectivity API surface.
+ *
+ * The annotations are maintained in a separate class so that it can be built as
+ * a separate library that other modules can build against, as Typedef should not
+ * be exposed as SystemApi.
+ *
+ * @hide
+ */
+public final class ConnectivityAnnotations {
+ private ConnectivityAnnotations() {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER,
+ ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY,
+ ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE,
+ })
+ public @interface MultipathPreference {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, value = {
+ ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED,
+ ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+ ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED,
+ })
+ public @interface RestrictBackgroundStatus {}
+}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index df81603..93455bc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -40,6 +40,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityAnnotations.MultipathPreference;
+import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.SocketKeepalive.Callback;
@@ -1431,10 +1433,18 @@
* Returns an array of all {@link Network} currently tracked by the
* framework.
*
+ * @deprecated This method does not provide any notification of network state changes, forcing
+ * apps to call it repeatedly. This is inefficient and prone to race conditions.
+ * Apps should use methods such as
+ * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} instead.
+ * Apps that desire to obtain information about networks that do not apply to them
+ * can use {@link NetworkRequest.Builder#setIncludeOtherUidNetworks}.
+ *
* @return an array of {@link Network} objects.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@NonNull
+ @Deprecated
public Network[] getAllNetworks() {
try {
return mService.getAllNetworks();
@@ -4799,16 +4809,6 @@
MULTIPATH_PREFERENCE_RELIABILITY |
MULTIPATH_PREFERENCE_PERFORMANCE;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- MULTIPATH_PREFERENCE_HANDOVER,
- MULTIPATH_PREFERENCE_RELIABILITY,
- MULTIPATH_PREFERENCE_PERFORMANCE,
- })
- public @interface MultipathPreference {
- }
-
/**
* Provides a hint to the calling application on whether it is desirable to use the
* multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
@@ -5030,16 +5030,6 @@
public static final String ACTION_RESTRICT_BACKGROUND_CHANGED =
"android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, value = {
- RESTRICT_BACKGROUND_STATUS_DISABLED,
- RESTRICT_BACKGROUND_STATUS_WHITELISTED,
- RESTRICT_BACKGROUND_STATUS_ENABLED,
- })
- public @interface RestrictBackgroundStatus {
- }
-
/**
* Determines if the calling application is subject to metered network restrictions while
* running on background.
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
index 07754e4..1a69099 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -27,7 +27,7 @@
import android.annotation.SystemApi;
import android.content.ContentResolver;
import android.content.Context;
-import android.net.ConnectivityManager.MultipathPreference;
+import android.net.ConnectivityAnnotations.MultipathPreference;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
@@ -43,7 +43,6 @@
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
-import java.util.regex.Pattern;
/**
* A manager class for connectivity module settings.
@@ -375,11 +374,12 @@
private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
/**
- * A list of apps that should be granted netd system permission for using restricted networks.
+ * A list of apps that is allowed on restricted networks.
*
* @hide
*/
- public static final String RESTRICTED_ALLOWED_APPS = "restricted_allowed_apps";
+ public static final String APPS_ALLOWED_ON_RESTRICTED_NETWORKS =
+ "apps_allowed_on_restricted_networks";
/**
* Get mobile data activity timeout from {@link Settings}.
@@ -1047,17 +1047,16 @@
}
/**
- * Get the list of apps(from {@link Settings}) that should be granted netd system permission for
- * using restricted networks.
+ * Get the list of apps(from {@link Settings}) that is allowed on restricted networks.
*
* @param context The {@link Context} to query the setting.
- * @return A list of apps that should be granted netd system permission for using restricted
- * networks or null if no setting value.
+ * @return A list of apps that is allowed on restricted networks or null if no setting
+ * value.
*/
@NonNull
- public static Set<String> getRestrictedAllowedApps(@NonNull Context context) {
+ public static Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) {
final String appList = Settings.Secure.getString(
- context.getContentResolver(), RESTRICTED_ALLOWED_APPS);
+ context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS);
if (TextUtils.isEmpty(appList)) {
return new ArraySet<>();
}
@@ -1065,27 +1064,24 @@
}
/**
- * Set the list of apps(from {@link Settings}) that should be granted netd system permission for
- * using restricted networks.
+ * Set the list of apps(from {@link Settings}) that is allowed on restricted networks.
*
* Note: Please refer to android developer guidelines for valid app(package name).
* https://developer.android.com/guide/topics/manifest/manifest-element.html#package
*
* @param context The {@link Context} to set the setting.
- * @param list A list of apps that should be granted netd system permission for using
- * restricted networks.
+ * @param list A list of apps that is allowed on restricted networks.
*/
- public static void setRestrictedAllowedApps(@NonNull Context context,
+ public static void setAppsAllowedOnRestrictedNetworks(@NonNull Context context,
@NonNull Set<String> list) {
- final Pattern appPattern = Pattern.compile("[a-zA-Z_0-9]+([.][a-zA-Z_0-9]+)*");
final StringJoiner joiner = new StringJoiner(";");
for (String app : list) {
- if (!appPattern.matcher(app).matches()) {
+ if (app == null || app.contains(";")) {
throw new IllegalArgumentException("Invalid app(package name)");
}
joiner.add(app);
}
- Settings.Secure.putString(
- context.getContentResolver(), RESTRICTED_ALLOWED_APPS, joiner.toString());
+ Settings.Secure.putString(context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS,
+ joiner.toString());
}
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 2e4d8f8..4932952 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -2416,6 +2416,11 @@
return mTransportInfo.getApplicableRedactions();
}
+ private NetworkCapabilities removeDefaultCapabilites() {
+ mNetworkCapabilities &= ~DEFAULT_CAPABILITIES;
+ return this;
+ }
+
/**
* Builder class for NetworkCapabilities.
*
@@ -2452,6 +2457,16 @@
}
/**
+ * Creates a new Builder without the default capabilities.
+ */
+ @NonNull
+ public static Builder withoutDefaultCapabilities() {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.removeDefaultCapabilites();
+ return new Builder(nc);
+ }
+
+ /**
* Adds the given transport type.
*
* Multiple transports may be added. Note that when searching for a network to satisfy a
@@ -2512,17 +2527,6 @@
}
/**
- * Completely clears the contents of this object, removing even the capabilities that are
- * set by default when the object is constructed.
- * @return this builder
- */
- @NonNull
- public Builder clearAll() {
- mCaps.clearAll();
- return this;
- }
-
- /**
* Sets the owner UID.
*
* The default value is {@link Process#INVALID_UID}. Pass this value to reset.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index a384109..a71dbbf 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -287,10 +287,15 @@
}
/**
- * Set the watched UIDs for this request. This will be reset and wiped out unless
- * the calling app holds the CHANGE_NETWORK_STATE permission.
+ * Sets this request to match only networks that apply to the specified UIDs.
*
- * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
+ * By default, the set of UIDs is the UID of the calling app, and this request will match
+ * any network that applies to the app. Setting it to {@code null} will observe any
+ * network on the system, even if it does not apply to this app. In this case, any
+ * {@link NetworkSpecifier} set on this request will be redacted or removed to prevent the
+ * application deducing restricted information such as location.
+ *
+ * @param uids The UIDs as a set of {@code Range<Integer>}, or null for everything.
* @return The builder to facilitate chaining.
* @hide
*/
@@ -517,6 +522,30 @@
mNetworkCapabilities.setSubscriptionIds(subIds);
return this;
}
+
+ /**
+ * Specifies whether the built request should also match networks that do not apply to the
+ * calling UID.
+ *
+ * By default, the built request will only match networks that apply to the calling UID.
+ * If this method is called with {@code true}, the built request will match any network on
+ * the system that matches the other parameters of the request. In this case, any
+ * information in the built request that is subject to redaction for security or privacy
+ * purposes, such as a {@link NetworkSpecifier}, will be redacted or removed to prevent the
+ * application deducing sensitive information.
+ *
+ * @param include Whether to match networks that do not apply to the calling UID.
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public Builder setIncludeOtherUidNetworks(boolean include) {
+ if (include) {
+ mNetworkCapabilities.setUids(null);
+ } else {
+ mNetworkCapabilities.setSingleUid(Process.myUid());
+ }
+ return this;
+ }
}
// implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java
index ab55002..957c867 100644
--- a/packages/Connectivity/framework/src/android/net/QosFilter.java
+++ b/packages/Connectivity/framework/src/android/net/QosFilter.java
@@ -71,5 +71,16 @@
*/
public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
int startPort, int endPort);
+
+ /**
+ * Determines whether or not the parameters is a match for the filter.
+ *
+ * @param address the remote address
+ * @param startPort the start of the port range
+ * @param endPort the end of the port range
+ * @return whether the parameters match the remote address of the filter
+ */
+ public abstract boolean matchesRemoteAddress(@NonNull InetAddress address,
+ int startPort, int endPort);
}
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
index 2080e68..69da7f4 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
@@ -138,13 +138,26 @@
if (mQosSocketInfo.getLocalSocketAddress() == null) {
return false;
}
-
- return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+ return matchesAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
endPort);
}
/**
- * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+ * @inheritDoc
+ */
+ @Override
+ public boolean matchesRemoteAddress(@NonNull final InetAddress address, final int startPort,
+ final int endPort) {
+ if (mQosSocketInfo.getRemoteSocketAddress() == null) {
+ return false;
+ }
+ return matchesAddress(mQosSocketInfo.getRemoteSocketAddress(), address, startPort,
+ endPort);
+ }
+
+ /**
+ * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)}
+ * and {@link QosSocketFilter#matchesRemoteAddress(InetAddress, int, int)} with the
* filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
* <p>
* This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
@@ -156,7 +169,7 @@
* @param endPort the end of the port range to check
*/
@VisibleForTesting
- public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+ public static boolean matchesAddress(@NonNull final InetSocketAddress filterSocketAddress,
@NonNull final InetAddress address,
final int startPort, final int endPort) {
return startPort <= filterSocketAddress.getPort()
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
index 53d9669..a45d507 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
@@ -32,7 +33,8 @@
/**
* Used in conjunction with
* {@link ConnectivityManager#registerQosCallback}
- * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}
+ * and/or remote address and port of a connected {@link Socket}.
*
* @hide
*/
@@ -48,6 +50,9 @@
@NonNull
private final InetSocketAddress mLocalSocketAddress;
+ @Nullable
+ private final InetSocketAddress mRemoteSocketAddress;
+
/**
* The {@link Network} the socket is on.
*
@@ -81,6 +86,18 @@
}
/**
+ * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+ * The value does not reflect any changes that occur to the socket after it is first set
+ * in the constructor.
+ *
+ * @return the remote address of the socket if socket is connected, null otherwise
+ */
+ @Nullable
+ public InetSocketAddress getRemoteSocketAddress() {
+ return mRemoteSocketAddress;
+ }
+
+ /**
* Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
* {@link Socket} must remain bound in order to receive {@link QosSession}s.
*
@@ -95,6 +112,12 @@
mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
mLocalSocketAddress =
new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+
+ if (socket.isConnected()) {
+ mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
+ } else {
+ mRemoteSocketAddress = null;
+ }
}
/* Parcelable methods */
@@ -102,11 +125,15 @@
mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
- final int addressLength = in.readInt();
- mLocalSocketAddress = readSocketAddress(in, addressLength);
+ final int localAddressLength = in.readInt();
+ mLocalSocketAddress = readSocketAddress(in, localAddressLength);
+
+ final int remoteAddressLength = in.readInt();
+ mRemoteSocketAddress = remoteAddressLength == 0 ? null
+ : readSocketAddress(in, remoteAddressLength);
}
- private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+ private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
final byte[] address = new byte[addressLength];
in.readByteArray(address);
final int port = in.readInt();
@@ -130,10 +157,19 @@
mNetwork.writeToParcel(dest, 0);
mParcelFileDescriptor.writeToParcel(dest, 0);
- final byte[] address = mLocalSocketAddress.getAddress().getAddress();
- dest.writeInt(address.length);
- dest.writeByteArray(address);
+ final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress();
+ dest.writeInt(localAddress.length);
+ dest.writeByteArray(localAddress);
dest.writeInt(mLocalSocketAddress.getPort());
+
+ if (mRemoteSocketAddress == null) {
+ dest.writeInt(0);
+ } else {
+ final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress();
+ dest.writeInt(remoteAddress.length);
+ dest.writeByteArray(remoteAddress);
+ dest.writeInt(mRemoteSocketAddress.getPort());
+ }
}
@NonNull
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index 813a239..7265426 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -65,6 +65,7 @@
"stable.core.platform.api.stubs",
"android_system_server_stubs_current",
"framework-annotations-lib",
+ "framework-connectivity-annotations",
"framework-connectivity.impl",
"framework-tethering.stubs.module_lib",
"framework-wifi.stubs.module_lib",
diff --git a/packages/Connectivity/service/src/com/android/server/ConnectivityService.java b/packages/Connectivity/service/src/com/android/server/ConnectivityService.java
index ed2fe82..daf231f 100644
--- a/packages/Connectivity/service/src/com/android/server/ConnectivityService.java
+++ b/packages/Connectivity/service/src/com/android/server/ConnectivityService.java
@@ -105,12 +105,12 @@
import android.net.CaptivePortal;
import android.net.CaptivePortalData;
import android.net.ConnectionInfo;
+import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.BlockedReason;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityManager.RestrictBackgroundStatus;
import android.net.ConnectivityResources;
import android.net.ConnectivitySettingsManager;
import android.net.DataStallReportParcelable;
@@ -1045,14 +1045,10 @@
} else {
// ConnectivityService publishes binder service using publishBinderService() with
// no priority assigned will be treated as NORMAL priority. Dumpsys does not send
- // "--dump-priority" arguments to the service. Thus, dump both NORMAL and HIGH to
- // align the legacy design.
+ // "--dump-priority" arguments to the service. Thus, dump NORMAL only to align the
+ // legacy output for dumpsys connectivity.
// TODO: Integrate into signal dump.
dumpNormal(fd, pw, args);
- pw.println();
- pw.println("DUMP OF SERVICE HIGH connectivity");
- pw.println();
- dumpHigh(fd, pw);
}
}
}
@@ -1395,7 +1391,7 @@
// arguments like the handler or the DnsResolver.
// TODO : remove this ; it is probably better handled with a sentinel request.
mNoServiceNetwork = new NetworkAgentInfo(null,
- new Network(NO_SERVICE_NET_ID),
+ new Network(INetd.UNREACHABLE_NET_ID),
new NetworkInfo(TYPE_NONE, 0, "", ""),
new LinkProperties(), new NetworkCapabilities(),
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
@@ -2156,10 +2152,22 @@
private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
int callerUid, String callerPackageName) {
+ // There is no need to track the effective UID of the request here. If the caller
+ // lacks the settings permission, the effective UID is the same as the calling ID.
if (!checkSettingsPermission()) {
- // There is no need to track the effective UID of the request here. If the caller lacks
- // the settings permission, the effective UID is the same as the calling ID.
- nc.setSingleUid(callerUid);
+ // Unprivileged apps can only pass in null or their own UID.
+ if (nc.getUids() == null) {
+ // If the caller passes in null, the callback will also match networks that do not
+ // apply to its UID, similarly to what it would see if it called getAllNetworks.
+ // In this case, redact everything in the request immediately. This ensures that the
+ // app is not able to get any redacted information by filing an unredacted request
+ // and observing whether the request matches something.
+ if (nc.getNetworkSpecifier() != null) {
+ nc.setNetworkSpecifier(nc.getNetworkSpecifier().redact());
+ }
+ } else {
+ nc.setSingleUid(callerUid);
+ }
}
nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
nc.setAdministratorUids(new int[0]);
@@ -6466,8 +6474,6 @@
// Request used to optionally keep vehicle internal network always active
private final NetworkRequest mDefaultVehicleRequest;
- // TODO replace with INetd.UNREACHABLE_NET_ID when available.
- private static final int NO_SERVICE_NET_ID = 52;
// Sentinel NAI used to direct apps with default networks that should have no connectivity to a
// network with no service. This NAI should never be matched against, nor should any public API
// ever return the associated network. For this reason, this NAI is not in the list of available
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
index a4085cde..d7eb9c8 100644
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -237,9 +237,9 @@
partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY),
accepted, rejected);
if (accepted.size() > 0) {
- // Some networks are primary. For each transport, keep only the primary, but also
- // keep all networks for which there isn't a primary (which are now in the |rejected|
- // array).
+ // Some networks are primary for their transport. For each transport, keep only the
+ // primary, but also keep all networks for which there isn't a primary (which are now
+ // in the |rejected| array).
// So for each primary network, remove from |rejected| all networks with the same
// transports as one of the primary networks. The remaining networks should be accepted.
for (final T defaultSubNai : accepted) {
@@ -247,6 +247,8 @@
rejected.removeIf(
nai -> Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
}
+ // Now the |rejected| list contains networks with transports for which there isn't
+ // a primary network. Add them back to the candidates.
accepted.addAll(rejected);
candidates = new ArrayList<>(accepted);
}
diff --git a/packages/Connectivity/test/Android.bp b/packages/Connectivity/test/Android.bp
deleted file mode 100644
index a6cad2e..0000000
--- a/packages/Connectivity/test/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// 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 {
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-// defaults for tests that need to build against framework-connectivity's @hide APIs
-// Only usable from targets that have visibility on framework-connectivity.impl.
-// Instead of using this, consider avoiding to depend on hidden connectivity APIs in
-// tests.
-java_defaults {
- name: "framework-connectivity-test-defaults",
- sdk_version: "core_platform", // tests can use @CorePlatformApi's
- libs: [
- // order matters: classes in framework-connectivity are resolved before framework,
- // meaning @hide APIs in framework-connectivity are resolved before @SystemApi
- // stubs in framework
- "framework-connectivity.impl",
- "framework",
-
- // if sdk_version="" this gets automatically included, but here we need to add manually.
- "framework-res",
- ],
-}
diff --git a/packages/Connectivity/tests/common/Android.bp b/packages/Connectivity/tests/common/Android.bp
index 439665b..7331453 100644
--- a/packages/Connectivity/tests/common/Android.bp
+++ b/packages/Connectivity/tests/common/Android.bp
@@ -46,3 +46,22 @@
"android.test.base.stubs",
],
}
+
+// defaults for tests that need to build against framework-connectivity's @hide APIs
+// Only usable from targets that have visibility on framework-connectivity.impl.
+// Instead of using this, consider avoiding to depend on hidden connectivity APIs in
+// tests.
+java_defaults {
+ name: "framework-connectivity-test-defaults",
+ sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ libs: [
+ // order matters: classes in framework-connectivity are resolved before framework,
+ // meaning @hide APIs in framework-connectivity are resolved before @SystemApi
+ // stubs in framework
+ "framework-connectivity.impl",
+ "framework",
+
+ // if sdk_version="" this gets automatically included, but here we need to add manually.
+ "framework-res",
+ ],
+}
diff --git a/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java b/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java
index ad58960..40f8f1b 100644
--- a/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java
+++ b/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java
@@ -35,7 +35,7 @@
public void testPortExactMatch() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertTrue(QosSocketFilter.matchesLocalAddress(
+ assertTrue(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
}
@@ -44,7 +44,7 @@
public void testPortLessThanStart() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertFalse(QosSocketFilter.matchesLocalAddress(
+ assertFalse(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 8), addressB, 10, 10));
}
@@ -52,7 +52,7 @@
public void testPortGreaterThanEnd() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertFalse(QosSocketFilter.matchesLocalAddress(
+ assertFalse(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 18), addressB, 10, 10));
}
@@ -60,7 +60,7 @@
public void testPortBetweenStartAndEnd() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertTrue(QosSocketFilter.matchesLocalAddress(
+ assertTrue(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 10), addressB, 8, 18));
}
@@ -68,7 +68,7 @@
public void testAddressesDontMatch() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
- assertFalse(QosSocketFilter.matchesLocalAddress(
+ assertFalse(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
}
}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 63501d7..29a411e 100644
--- a/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -128,6 +128,7 @@
import static com.android.testutils.MiscAsserts.assertEmpty;
import static com.android.testutils.MiscAsserts.assertLength;
import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
+import static com.android.testutils.MiscAsserts.assertSameElements;
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertEquals;
@@ -4276,6 +4277,124 @@
mCm.unregisterNetworkCallback(callback);
}
+ @Test
+ public void testNetworkCallbackWithNullUids() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Attempt to file a callback for networks applying to another UID. This does not actually
+ // work, because this code does not currently have permission to do so. The callback behaves
+ // exactly the same as the one registered just above.
+ final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
+ final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
+ .build();
+ final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
+
+ final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .setIncludeOtherUidNetworks(true)
+ .build();
+ final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(includeOtherUidsRequest, includeOtherUidsCallback);
+
+ // Both callbacks see a network with no specifier that applies to their UID.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ includeOtherUidsCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ otherUidCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+
+ // Only the includeOtherUidsCallback sees a VPN that does not apply to its UID.
+ final UidRange range = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
+ final Set<UidRange> vpnRanges = Collections.singleton(range);
+ mMockVpn.establish(new LinkProperties(), VPN_UID, vpnRanges);
+ includeOtherUidsCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ callback.assertNoCallback();
+ otherUidCallback.assertNoCallback();
+
+ mMockVpn.disconnect();
+ includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ callback.assertNoCallback();
+ otherUidCallback.assertNoCallback();
+ }
+
+ private static class RedactableNetworkSpecifier extends NetworkSpecifier {
+ public static final int ID_INVALID = -1;
+
+ public final int networkId;
+
+ RedactableNetworkSpecifier(int networkId) {
+ this.networkId = networkId;
+ }
+
+ @Override
+ public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+ return other instanceof RedactableNetworkSpecifier
+ && this.networkId == ((RedactableNetworkSpecifier) other).networkId;
+ }
+
+ @Override
+ public NetworkSpecifier redact() {
+ return new RedactableNetworkSpecifier(ID_INVALID);
+ }
+ }
+
+ @Test
+ public void testNetworkCallbackWithNullUidsRedactsSpecifier() throws Exception {
+ final RedactableNetworkSpecifier specifier = new RedactableNetworkSpecifier(42);
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_WIFI)
+ .setNetworkSpecifier(specifier)
+ .build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Attempt to file a callback for networks applying to another UID. This does not actually
+ // work, because this code does not currently have permission to do so. The callback behaves
+ // exactly the same as the one registered just above.
+ final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
+ final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_WIFI)
+ .setNetworkSpecifier(specifier)
+ .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
+ .build();
+ final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
+
+ final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_WIFI)
+ .setNetworkSpecifier(specifier)
+ .setIncludeOtherUidNetworks(true)
+ .build();
+ final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(includeOtherUidsRequest, callback);
+
+ // Only the regular callback sees the network, because callbacks filed with no UID have
+ // their specifiers redacted.
+ final LinkProperties emptyLp = new LinkProperties();
+ final NetworkCapabilities ncTemplate = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setNetworkSpecifier(specifier);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, emptyLp, ncTemplate);
+ mWiFiNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ includeOtherUidsCallback.assertNoCallback();
+ }
+
private void setCaptivePortalMode(int mode) {
ContentResolver cr = mServiceContext.getContentResolver();
Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
@@ -5885,20 +6004,8 @@
mCm.unregisterNetworkCallback(networkCallback);
}
- private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) {
- // Easier to implement than a proper "assertSameElements" method that also correctly deals
- // with duplicates.
- final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual);
- assertEquals(msg, expected.length, actual.length);
- Set expectedSet = new ArraySet<>(Arrays.asList(expected));
- assertEquals("expected contains duplicates", expectedSet.size(), expected.length);
- // actual cannot have duplicates because it's the same length and has the same elements.
- Set actualSet = new ArraySet<>(Arrays.asList(actual));
- assertEquals(expectedSet, actualSet);
- }
-
- private void expectNetworkStatus(Network[] networks, String defaultIface,
- Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
+ private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface,
+ Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
ArgumentCaptor.forClass(List.class);
@@ -5906,26 +6013,24 @@
verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
- assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks);
+ assertSameElements(networksCaptor.getValue(), networks);
- UnderlyingNetworkInfo[] infos =
- vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]);
+ List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
- assertEquals("Should have exactly one VPN:", 1, infos.length);
- UnderlyingNetworkInfo info = infos[0];
+ assertEquals("Should have exactly one VPN:", 1, infos.size());
+ UnderlyingNetworkInfo info = infos.get(0);
assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid());
assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface());
- assertSameElementsNoDuplicates(underlyingIfaces,
- info.getUnderlyingInterfaces().toArray(new String[0]));
+ assertSameElements(underlyingIfaces, info.getUnderlyingInterfaces());
} else {
- assertEquals(0, infos.length);
+ assertEquals(0, infos.size());
return;
}
}
- private void expectNetworkStatus(
- Network[] networks, String defaultIface) throws Exception {
- expectNetworkStatus(networks, defaultIface, null, null, new String[0]);
+ private void expectNotifyNetworkStatus(
+ List<Network> networks, String defaultIface) throws Exception {
+ expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of());
}
@Test
@@ -5933,8 +6038,8 @@
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
- final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
+ final List<Network> onlyCell = List.of(mCellNetworkAgent.getNetwork());
+ final List<Network> onlyWifi = List.of(mWiFiNetworkAgent.getNetwork());
LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -5945,7 +6050,7 @@
mCellNetworkAgent.connect(false);
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
reset(mStatsManager);
// Default network switch should update ifaces.
@@ -5953,37 +6058,37 @@
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNetworkStatus(onlyWifi, WIFI_IFNAME);
+ expectNotifyNetworkStatus(onlyWifi, WIFI_IFNAME);
reset(mStatsManager);
// Disconnect should update ifaces.
mWiFiNetworkAgent.disconnect();
waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
reset(mStatsManager);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
reset(mStatsManager);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
reset(mStatsManager);
// Temp metered change shouldn't update ifaces
mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
waitForIdle();
- verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
+ verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell),
any(List.class), eq(MOBILE_IFNAME), any(List.class));
reset(mStatsManager);
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
reset(mStatsManager);
// Test VPNs.
@@ -5993,29 +6098,29 @@
mMockVpn.establishForMyUid(lp);
assertUidRangesUpdatedForMyUid(true);
- final Network[] cellAndVpn = new Network[] {
- mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
+ final List<Network> cellAndVpn =
+ List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork());
// A VPN with default (null) underlying networks sets the underlying network's interfaces...
- expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
+ expectNotifyNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(MOBILE_IFNAME));
// ...and updates them as the default network switches.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
final Network[] onlyNull = new Network[]{null};
- final Network[] wifiAndVpn = new Network[] {
- mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
- final Network[] cellAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
- final Network[] cellNullAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
+ final List<Network> wifiAndVpn =
+ List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork());
+ final List<Network> cellAndWifi =
+ List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork());
+ final Network[] cellNullAndWifi =
+ new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{WIFI_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(WIFI_IFNAME));
reset(mStatsManager);
// A VPN that sets its underlying networks passes the underlying interfaces, and influences
@@ -6024,23 +6129,23 @@
// MOBILE_IFNAME even though the default network is wifi.
// TODO: fix this to pass in the actual default network interface. Whether or not the VPN
// applies to the system server UID should not have any bearing on network stats.
- mMockVpn.setUnderlyingNetworks(onlyCell);
+ mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(MOBILE_IFNAME));
reset(mStatsManager);
- mMockVpn.setUnderlyingNetworks(cellAndWifi);
+ mMockVpn.setUnderlyingNetworks(cellAndWifi.toArray(new Network[0]));
waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(MOBILE_IFNAME, WIFI_IFNAME));
reset(mStatsManager);
// Null underlying networks are ignored.
mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(MOBILE_IFNAME, WIFI_IFNAME));
reset(mStatsManager);
// If an underlying network disconnects, that interface should no longer be underlying.
@@ -6053,8 +6158,8 @@
mCellNetworkAgent.disconnect();
waitForIdle();
assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(MOBILE_IFNAME, WIFI_IFNAME));
// Confirm that we never tell NetworkStatsService that cell is no longer the underlying
// network for the VPN...
@@ -6089,26 +6194,26 @@
// Also, for the same reason as above, the active interface passed in is null.
mMockVpn.setUnderlyingNetworks(new Network[0]);
waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
+ expectNotifyNetworkStatus(wifiAndVpn, null);
reset(mStatsManager);
// Specifying only a null underlying network is the same as no networks.
mMockVpn.setUnderlyingNetworks(onlyNull);
waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
+ expectNotifyNetworkStatus(wifiAndVpn, null);
reset(mStatsManager);
// Specifying networks that are all disconnected is the same as specifying no networks.
- mMockVpn.setUnderlyingNetworks(onlyCell);
+ mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
+ expectNotifyNetworkStatus(wifiAndVpn, null);
reset(mStatsManager);
// Passing in null again means follow the default network again.
mMockVpn.setUnderlyingNetworks(null);
waitForIdle();
- expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{WIFI_IFNAME});
+ expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ List.of(WIFI_IFNAME));
reset(mStatsManager);
}
diff --git a/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml b/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml
index a19f7af..22b25a3 100644
--- a/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml
@@ -23,4 +23,15 @@
column="15"/>
</issue>
+ <issue
+ id="NewApi"
+ message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
+ errorLine1=" android:radius="?android:attr/dialogCornerRadius""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/settingslib_rounded_background.xml"
+ line="23"
+ column="9"/>
+ </issue>
+
</issues>
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/settingslib_rounded_background.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/settingslib_rounded_background.xml
new file mode 100644
index 0000000..ae3834d
--- /dev/null
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/settingslib_rounded_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners
+ android:radius="?android:attr/dialogCornerRadius"
+ />
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml b/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml
new file mode 100644
index 0000000..ba612d7
--- /dev/null
+++ b/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:paddingHorizontal="8dp"
+ android:orientation="horizontal"
+ android:background="@drawable/settingslib_rounded_background">
+
+ <Button
+ android:id="@+id/button1"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <View
+ android:id="@+id/divider1"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="4dp"
+ android:visibility="gone"
+ android:background="?android:colorBackground" />
+
+ <Button
+ android:id="@+id/button2"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <View
+ android:id="@+id/divider2"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="4dp"
+ android:visibility="gone"
+ android:background="?android:colorBackground" />
+
+ <Button
+ android:id="@+id/button3"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <View
+ android:id="@+id/divider3"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="4dp"
+ android:visibility="gone"
+ android:background="?android:colorBackground" />
+
+ <Button
+ android:id="@+id/button4"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+</LinearLayout>
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/layout/settings_action_buttons.xml b/packages/SettingsLib/ActionButtonsPreference/res/layout/settingslib_action_buttons.xml
similarity index 88%
rename from packages/SettingsLib/ActionButtonsPreference/res/layout/settings_action_buttons.xml
rename to packages/SettingsLib/ActionButtonsPreference/res/layout/settingslib_action_buttons.xml
index 4f47113..55df34f 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/layout/settings_action_buttons.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/layout/settingslib_action_buttons.xml
@@ -24,29 +24,29 @@
<Button
android:id="@+id/button1"
- style="@style/SettingsActionButton"
+ style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/button2"
- style="@style/SettingsActionButton"
+ style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/button3"
- style="@style/SettingsActionButton"
+ style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/button4"
- style="@style/SettingsActionButton"
+ style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml b/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
index efa508d..42c7d76 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
@@ -16,11 +16,10 @@
-->
<resources>
- <style name="SettingsActionButton" parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
+ <style name="SettingsLibActionButton" parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
<item name="android:drawablePadding">4dp</item>
<item name="android:drawableTint">@*android:color/btn_colored_borderless_text_material</item>
- <item name="android:layout_marginEnd">8dp</item>
<item name="android:paddingTop">20dp</item>
<item name="android:paddingBottom">20dp</item>
</style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
index 8b46cc6..aeda7ac 100644
--- a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
+++ b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
@@ -27,16 +27,20 @@
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
+import androidx.core.os.BuildCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This preference provides a four buttons layout with Settings style.
* It looks like below
*
- * --------------------------------------------------
- * button1 | button2 | button3 | button4 |
- * --------------------------------------------------
+ * ---------------------------------------
+ * - button1 | button2 | button3 | button4 -
+ * ---------------------------------------
*
* User can set title / icon / click listener for each button.
*
@@ -49,10 +53,16 @@
public class ActionButtonsPreference extends Preference {
private static final String TAG = "ActionButtonPreference";
+
private final ButtonInfo mButton1Info = new ButtonInfo();
private final ButtonInfo mButton2Info = new ButtonInfo();
private final ButtonInfo mButton3Info = new ButtonInfo();
private final ButtonInfo mButton4Info = new ButtonInfo();
+ private final List<ButtonInfo> mVisibleButtonInfos = new ArrayList<>(4);
+
+ private View mDivider1;
+ private View mDivider2;
+ private View mDivider3;
public ActionButtonsPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
@@ -76,25 +86,49 @@
}
private void init() {
- setLayoutResource(R.layout.settings_action_buttons);
+ setLayoutResource(R.layout.settingslib_action_buttons);
setSelectable(false);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- holder.setDividerAllowedAbove(true);
- holder.setDividerAllowedBelow(true);
+ if (!BuildCompat.isAtLeastS()) {
+ holder.setDividerAllowedAbove(true);
+ holder.setDividerAllowedBelow(true);
+ }
mButton1Info.mButton = (Button) holder.findViewById(R.id.button1);
mButton2Info.mButton = (Button) holder.findViewById(R.id.button2);
mButton3Info.mButton = (Button) holder.findViewById(R.id.button3);
mButton4Info.mButton = (Button) holder.findViewById(R.id.button4);
+ mDivider1 = holder.findViewById(R.id.divider1);
+ mDivider2 = holder.findViewById(R.id.divider2);
+ mDivider3 = holder.findViewById(R.id.divider3);
+
mButton1Info.setUpButton();
mButton2Info.setUpButton();
mButton3Info.setUpButton();
mButton4Info.setUpButton();
+
+ // Add visible button into list only
+ if (mButton1Info.isVisible()) {
+ mVisibleButtonInfos.add(mButton1Info);
+ }
+ if (mButton2Info.isVisible()) {
+ mVisibleButtonInfos.add(mButton2Info);
+ }
+ if (mButton3Info.isVisible()) {
+ mVisibleButtonInfos.add(mButton3Info);
+ }
+ if (mButton4Info.isVisible()) {
+ mVisibleButtonInfos.add(mButton4Info);
+ }
+
+ setupDivider1();
+ setupDivider2();
+ setupDivider3();
}
/**
@@ -357,6 +391,28 @@
return this;
}
+ private void setupDivider1() {
+ // Display divider1 only if button1 and button2 is visible
+ if (mDivider1 != null && mButton1Info.isVisible() && mButton2Info.isVisible()) {
+ mDivider1.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void setupDivider2() {
+ // Display divider2 only if button3 is visible and button2 or button3 is visible
+ if (mDivider2 != null && mButton3Info.isVisible()
+ && (mButton1Info.isVisible() || mButton2Info.isVisible())) {
+ mDivider2.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void setupDivider3() {
+ // Display divider3 only if button4 is visible and 2 visible buttons at least
+ if (mDivider3 != null && mVisibleButtonInfos.size() > 1 && mButton4Info.isVisible()) {
+ mDivider3.setVisibility(View.VISIBLE);
+ }
+ }
+
static class ButtonInfo {
private Button mButton;
private CharSequence mText;
@@ -379,6 +435,10 @@
}
}
+ boolean isVisible() {
+ return mButton.getVisibility() == View.VISIBLE;
+ }
+
/**
* By default, four buttons are visible.
* However, there are two cases which button should be invisible.
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index 2cbb888..7d65aae 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -23,20 +23,13 @@
android:gravity="center"
android:orientation="horizontal">
- <View
- android:id="@+id/protection_layer"
- android:layout_width="412dp"
- android:layout_height="300dp"
- android:layout_gravity="center"
- android:padding="@dimen/settingslib_illustration_padding"
- android:background="@drawable/protection_background"/>
-
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
android:layout_width="412dp"
android:layout_height="300dp"
android:layout_gravity="center"
- android:padding="@dimen/settingslib_illustration_padding"
+ android:clipToOutline="true"
+ android:background="@drawable/protection_background"
android:importantForAccessibility="no"/>
<ImageView
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
index 900400e..b41762f 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
@@ -26,7 +26,7 @@
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
<solid
- android:color="@color/settingslib_state_off_color"
+ android:color="@color/settingslib_thumb_off_color"
android:alpha="?android:attr/disabledAlpha"/>
</shape>
</item>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
index e54c332..8b69ad1 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
@@ -25,7 +25,7 @@
<size
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
- <solid android:color="@color/settingslib_state_off_color"/>
+ <solid android:color="@color/settingslib_thumb_off_color"/>
</shape>
</item>
</layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 27c30ca6..010b9ba 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -19,10 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
- android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:background="?android:attr/colorBackground"
android:orientation="vertical">
@@ -31,15 +27,16 @@
android:minHeight="@dimen/settingslib_min_switch_bar_height"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:paddingLeft="@dimen/settingslib_switchbar_margin_start"
- android:paddingRight="@dimen/settingslib_switchbar_margin_end">
+ android:layout_margin="@dimen/settingslib_switchbar_margin"
+ android:paddingStart="@dimen/settingslib_switchbar_padding_left"
+ android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<TextView
android:id="@+id/switch_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
- android:layout_marginRight="16dp"
+ android:layout_marginEnd="16dp"
android:layout_gravity="center_vertical"
android:maxLines="2"
android:ellipsize="end"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
index c8d06d4..9ca3683 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
@@ -15,10 +15,16 @@
limitations under the License.
-->
-<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<resources>
<color name="settingslib_switchbar_switch_track_tint">#82000000</color>
<color name="settingslib_switchbar_switch_thumb_tint">@android:color/black</color>
+ <!-- Material next thumb off color-->
+ <color name="settingslib_thumb_off_color">@android:color/system_neutral2_300</color>
+
<!-- Material next track on color-->
- <color name="settingslib_track_on_color">?androidprv:attr/colorSurfaceHighlight</color>
+ <color name="settingslib_track_on_color">@android:color/system_accent2_700</color>
+
+ <!-- Material next track off color-->
+ <color name="settingslib_track_off_color">@android:color/system_neutral1_700</color>
</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
index 3fcc1dd..2c73238 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
@@ -26,9 +26,12 @@
<!-- Material next state off color-->
<color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
+ <!-- Material next thumb off color-->
+ <color name="settingslib_thumb_off_color">@android:color/system_neutral2_100</color>
+
<!-- Material next track on color-->
<color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
<!-- Material next track off color-->
- <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
+ <color name="settingslib_track_off_color">@android:color/system_neutral2_600</color>
</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 4c528da..a1cbcf72 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -17,11 +17,14 @@
<resources>
+ <!-- Size of layout margin -->
+ <dimen name="settingslib_switchbar_margin">16dp</dimen>
+
<!-- Size of layout margin left -->
- <dimen name="settingslib_switchbar_margin_start">24dp</dimen>
+ <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
<!-- Size of layout margin right -->
- <dimen name="settingslib_switchbar_margin_end">16dp</dimen>
+ <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">52dp</dimen>
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
index f6a64c6..21fcedc 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
@@ -23,16 +23,16 @@
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
- android:background="?android:attr/selectableItemBackground"
+ android:background="@android:color/transparent"
android:clipToPadding="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:clipToPadding="false"
- android:duplicateParentState="true"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
@@ -44,14 +44,12 @@
android:minWidth="56dp"
android:orientation="horizontal"
android:clipToPadding="false"
- android:duplicateParentState="true"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<androidx.preference.internal.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:duplicateParentState="true"
settings:maxWidth="48dp"
settings:maxHeight="48dp" />
</LinearLayout>
@@ -60,7 +58,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:duplicateParentState="true"
android:paddingTop="16dp"
android:paddingBottom="16dp">
@@ -69,7 +66,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:duplicateParentState="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
@@ -79,7 +75,6 @@
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
- android:duplicateParentState="true"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
@@ -95,7 +90,6 @@
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:duplicateParentState="true"
android:minWidth="64dp"
android:gravity="center"
android:orientation="vertical" />
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target_divider.xml b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target_divider.xml
index 44732e5..bd477f8 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target_divider.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target_divider.xml
@@ -22,12 +22,10 @@
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:orientation="horizontal"
- android:duplicateParentState="true"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<View
android:layout_width="1dp"
android:layout_height="match_parent"
- android:duplicateParentState="true"
android:background="?android:attr/listDivider" />
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
index e24b525..9f31cef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
@@ -48,7 +48,7 @@
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
- mRootView = View.inflate(mContext, R.layout.settings_action_buttons, null /* parent */);
+ mRootView = View.inflate(mContext, R.layout.settingslib_action_buttons, null /* parent */);
mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
mPref = new ActionButtonsPreference(mContext);
}
@@ -251,6 +251,114 @@
assertThat(drawablesAroundText[1 /* top */]).isNull();
}
+ @Test
+ public void onBindViewHolder_setAllButton_shouldShowAllDivider() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton2Text(R.string.install_other_apps);
+ mPref.setButton3Text(R.string.install_other_apps);
+ mPref.setButton4Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setAllButtonWithoutButton2_shouldHideDivider1() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton3Text(R.string.install_other_apps);
+ mPref.setButton4Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setAllButtonWithoutButton3_shouldHideDivider2() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton2Text(R.string.install_other_apps);
+ mPref.setButton4Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setButton1And4_shouldShowDivider3Only() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton4Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void onBindViewHolder_setOneButtonOnly_noDivider() {
+ mPref.setButton4Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void onBindViewHolder_setButton1And2_shouldShowDivider1Only() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton2Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void onBindViewHolder_setButton1And3_shouldShowDivider2Only() {
+ mPref.setButton1Text(R.string.install_other_apps);
+ mPref.setButton3Text(R.string.install_other_apps);
+
+ mPref.onBindViewHolder(mHolder);
+
+ assertThat(mRootView.findViewById(R.id.divider1).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.divider2).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mRootView.findViewById(R.id.divider3).getVisibility())
+ .isEqualTo(View.GONE);
+ }
+
public static ActionButtonsPreference createMock() {
final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
when(pref.setButton1Text(anyInt())).thenReturn(pref);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index b7560d2..c9c3db8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -73,6 +73,7 @@
Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER,
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
Settings.Global.USER_DISABLED_HDR_FORMATS,
- Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED
+ Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
+ Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 8f7f1fa..5220a04 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -139,6 +139,7 @@
/* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT,
/* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index df6ff73..00fd19c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -16,7 +16,11 @@
package com.android.providers.settings;
-import android.annotation.SystemApi;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
+
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.AttributionSource;
import android.content.IContentProvider;
@@ -41,10 +45,7 @@
/**
* Receives shell commands from the command line related to device config flags, and dispatches them
* to the SettingsProvider.
- *
- * @hide
*/
-@SystemApi
public final class DeviceConfigService extends Binder {
final SettingsProvider mProvider;
@@ -62,18 +63,20 @@
final SettingsProvider mProvider;
enum CommandVerb {
- UNSPECIFIED,
GET,
PUT,
DELETE,
LIST,
RESET,
+ SET_SYNC_DISABLED_FOR_TESTS,
+ IS_SYNC_DISABLED_FOR_TESTS,
}
MyShellCommand(SettingsProvider provider) {
mProvider = provider;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
@Override
public int onCommand(String cmd) {
if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
@@ -83,6 +86,7 @@
final PrintWriter perr = getErrPrintWriter();
boolean isValid = false;
+
CommandVerb verb;
if ("get".equalsIgnoreCase(cmd)) {
verb = CommandVerb.GET;
@@ -97,21 +101,33 @@
}
} else if ("reset".equalsIgnoreCase(cmd)) {
verb = CommandVerb.RESET;
+ } else if ("set_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.SET_SYNC_DISABLED_FOR_TESTS;
+ } else if ("is_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.IS_SYNC_DISABLED_FOR_TESTS;
+ if (peekNextArg() != null) {
+ perr.println("Bad arguments");
+ return -1;
+ }
+ isValid = true;
} else {
// invalid
perr.println("Invalid command: " + cmd);
return -1;
}
+ // Parse args for those commands that have them.
+ int disableSyncMode = -1;
int resetMode = -1;
boolean makeDefault = false;
String namespace = null;
String key = null;
String value = null;
- String arg = null;
+ String arg;
while ((arg = getNextArg()) != null) {
if (verb == CommandVerb.RESET) {
if (resetMode == -1) {
+ // RESET 1st arg (required)
if ("untrusted_defaults".equalsIgnoreCase(arg)) {
resetMode = Settings.RESET_MODE_UNTRUSTED_DEFAULTS;
} else if ("untrusted_clear".equalsIgnoreCase(arg)) {
@@ -127,6 +143,7 @@
isValid = true;
}
} else {
+ // RESET 2nd arg (optional)
namespace = arg;
if (peekNextArg() == null) {
isValid = true;
@@ -136,7 +153,26 @@
return -1;
}
}
+ } else if (verb == CommandVerb.SET_SYNC_DISABLED_FOR_TESTS) {
+ if (disableSyncMode == -1) {
+ // DISABLE_SYNC_FOR_TESTS 1st arg (required)
+ if ("none".equalsIgnoreCase(arg)) {
+ disableSyncMode = SYNC_DISABLED_MODE_NONE;
+ } else if ("persistent".equalsIgnoreCase(arg)) {
+ disableSyncMode = SYNC_DISABLED_MODE_PERSISTENT;
+ } else if ("until_reboot".equalsIgnoreCase(arg)) {
+ disableSyncMode = SYNC_DISABLED_MODE_UNTIL_REBOOT;
+ } else {
+ // invalid
+ perr.println("Invalid sync disabled mode: " + arg);
+ return -1;
+ }
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
+ }
} else if (namespace == null) {
+ // GET, PUT, DELETE, LIST 1st arg
namespace = arg;
if (verb == CommandVerb.LIST) {
if (peekNextArg() == null) {
@@ -148,8 +184,10 @@
}
}
} else if (key == null) {
+ // GET, PUT, DELETE 2nd arg
key = arg;
if ((verb == CommandVerb.GET || verb == CommandVerb.DELETE)) {
+ // GET, DELETE only have 2 args
if (peekNextArg() == null) {
isValid = true;
} else {
@@ -159,11 +197,13 @@
}
}
} else if (value == null) {
+ // PUT 3rd arg (required)
value = arg;
if (verb == CommandVerb.PUT && peekNextArg() == null) {
isValid = true;
}
} else if ("default".equalsIgnoreCase(arg)) {
+ // PUT 4th arg (optional)
makeDefault = true;
if (verb == CommandVerb.PUT && peekNextArg() == null) {
isValid = true;
@@ -211,6 +251,12 @@
case RESET:
DeviceConfig.resetToDefaults(resetMode, namespace);
break;
+ case SET_SYNC_DISABLED_FOR_TESTS:
+ DeviceConfig.setSyncDisabled(disableSyncMode);
+ break;
+ case IS_SYNC_DISABLED_FOR_TESTS:
+ pout.println(DeviceConfig.isSyncDisabled());
+ break;
default:
perr.println("Unspecified command");
return -1;
@@ -241,6 +287,16 @@
+ "trusted_defaults}");
pw.println(" NAMESPACE limits which flags are reset if provided, otherwise all "
+ "flags are reset");
+ pw.println(" set_sync_disabled_for_tests SYNC_DISABLED_MODE");
+ pw.println(" Modifies bulk property setting behavior for tests. When in one of the"
+ + " disabled modes this ensures that config isn't overwritten.");
+ pw.println(" SYNC_DISABLED_MODE is one of:");
+ pw.println(" none: Sync is not disabled. A reboot may be required to restart"
+ + " syncing.");
+ pw.println(" persistent: Sync is disabled, this state will survive a reboot.");
+ pw.println(" until_reboot: Sync is disabled until the next reboot.");
+ pw.println(" is_sync_disabled_for_tests");
+ pw.println(" Prints 'true' if sync is disabled, 'false' otherwise.");
}
private boolean delete(IContentProvider provider, String namespace, String key) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3219b2b..959b6ba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -19,6 +19,12 @@
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
+import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
+import static android.provider.Settings.SET_ALL_RESULT_DISABLED;
+import static android.provider.Settings.SET_ALL_RESULT_FAILURE;
+import static android.provider.Settings.SET_ALL_RESULT_SUCCESS;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER;
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
@@ -83,8 +89,10 @@
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
+import android.provider.Settings.SetAllResult;
import android.provider.settings.validators.SystemSettingsValidators;
import android.provider.settings.validators.Validator;
import android.text.TextUtils;
@@ -338,6 +346,9 @@
// We have to call in the package manager with no lock held,
private volatile IPackageManager mPackageManager;
+ @GuardedBy("mLock")
+ private boolean mSyncConfigDisabledUntilReboot;
+
public static int makeKey(int type, int userId) {
return SettingsState.makeKey(type, userId);
}
@@ -446,11 +457,24 @@
String prefix = getSettingPrefix(args);
Map<String, String> flags = getSettingFlags(args);
Bundle result = new Bundle();
- result.putBoolean(Settings.KEY_CONFIG_SET_RETURN,
+ result.putInt(Settings.KEY_CONFIG_SET_ALL_RETURN,
setAllConfigSettings(prefix, flags));
return result;
}
+ case Settings.CALL_METHOD_SET_SYNC_DISABLED_CONFIG: {
+ final int mode = getSyncDisabledMode(args);
+ setSyncDisabledConfig(mode);
+ break;
+ }
+
+ case Settings.CALL_METHOD_IS_SYNC_DISABLED_CONFIG: {
+ Bundle result = new Bundle();
+ result.putBoolean(Settings.KEY_CONFIG_IS_SYNC_DISABLED_RETURN,
+ isSyncDisabledConfig());
+ return result;
+ }
+
case Settings.CALL_METHOD_RESET_CONFIG: {
final int mode = getResetModeEnforcingPermission(args);
String prefix = getSettingPrefix(args);
@@ -1105,7 +1129,8 @@
MUTATION_OPERATION_INSERT, 0);
}
- private boolean setAllConfigSettings(String prefix, Map<String, String> keyValues) {
+
+ private @SetAllResult int setAllConfigSettings(String prefix, Map<String, String> keyValues) {
if (DEBUG) {
Slog.v(LOG_TAG, "setAllConfigSettings for prefix: " + prefix);
}
@@ -1113,9 +1138,95 @@
enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
synchronized (mLock) {
+ if (isSyncDisabledConfigLocked()) {
+ return SET_ALL_RESULT_DISABLED;
+ }
final int key = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
- return mSettingsRegistry.setConfigSettingsLocked(key, prefix, keyValues,
+ boolean success = mSettingsRegistry.setConfigSettingsLocked(key, prefix, keyValues,
resolveCallingPackage());
+ return success ? SET_ALL_RESULT_SUCCESS : SET_ALL_RESULT_FAILURE;
+ }
+ }
+
+ private void setSyncDisabledConfig(@SyncDisabledMode int syncDisabledMode) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "setSyncDisabledConfig(" + syncDisabledMode + ")");
+ }
+
+ enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
+
+ synchronized (mLock) {
+ setSyncDisabledConfigLocked(syncDisabledMode);
+ }
+ }
+
+ private boolean isSyncDisabledConfig() {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "isSyncDisabledConfig");
+ }
+
+ enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
+
+ synchronized (mLock) {
+ return isSyncDisabledConfigLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void setSyncDisabledConfigLocked(@SyncDisabledMode int syncDisabledMode) {
+ boolean persistentValue;
+ boolean inMemoryValue;
+ if (syncDisabledMode == SYNC_DISABLED_MODE_NONE) {
+ persistentValue = false;
+ inMemoryValue = false;
+ } else if (syncDisabledMode == SYNC_DISABLED_MODE_PERSISTENT) {
+ persistentValue = true;
+ inMemoryValue = false;
+ } else if (syncDisabledMode == SYNC_DISABLED_MODE_UNTIL_REBOOT) {
+ persistentValue = false;
+ inMemoryValue = true;
+ } else {
+ throw new IllegalArgumentException(Integer.toString(syncDisabledMode));
+ }
+
+ mSyncConfigDisabledUntilReboot = inMemoryValue;
+
+ CallingIdentity callingIdentity = clearCallingIdentity();
+ try {
+ String globalSettingValue = persistentValue ? "1" : "0";
+ mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
+ UserHandle.USER_SYSTEM, Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
+ globalSettingValue, /*tag=*/null, /*makeDefault=*/false,
+ SettingsState.SYSTEM_PACKAGE_NAME, /*forceNotify=*/false,
+ /*criticalSettings=*/null, Settings.DEFAULT_OVERRIDEABLE_BY_RESTORE);
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean isSyncDisabledConfigLocked() {
+ // Check the values used for both SYNC_DISABLED_MODE_PERSISTENT and
+ // SYNC_DISABLED_MODE_UNTIL_REBOOT.
+
+ // The SYNC_DISABLED_MODE_UNTIL_REBOOT value is cheap to check first.
+ if (mSyncConfigDisabledUntilReboot) {
+ return true;
+ }
+
+ // Now check the global setting used to implement SYNC_DISABLED_MODE_PERSISTENT.
+ CallingIdentity callingIdentity = clearCallingIdentity();
+ try {
+ Setting settingLocked = mSettingsRegistry.getSettingLocked(
+ SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM,
+ Global.DEVICE_CONFIG_SYNC_DISABLED);
+ if (settingLocked == null) {
+ return false;
+ }
+ String settingValue = settingLocked.getValue();
+ return settingValue != null && !"0".equals(settingValue);
+ } finally {
+ restoreCallingIdentity(callingIdentity);
}
}
@@ -2227,6 +2338,16 @@
return (args != null) && args.getBoolean(Settings.CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY);
}
+ private static int getSyncDisabledMode(Bundle args) {
+ final int mode = (args != null)
+ ? args.getInt(Settings.CALL_METHOD_SYNC_DISABLED_MODE_KEY) : -1;
+ if (mode == SYNC_DISABLED_MODE_NONE || mode == SYNC_DISABLED_MODE_UNTIL_REBOOT
+ || mode == SYNC_DISABLED_MODE_PERSISTENT) {
+ return mode;
+ }
+ throw new IllegalArgumentException("Invalid sync disabled mode: " + mode);
+ }
+
private static int getResetModeEnforcingPermission(Bundle args) {
final int mode = (args != null) ? args.getInt(Settings.CALL_METHOD_RESET_MODE_KEY) : 0;
switch (mode) {
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index 2191d93..ecd1369 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -29,6 +29,7 @@
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
+import android.view.WindowManager;
import android.widget.CheckBox;
import com.android.internal.app.AlertActivity;
@@ -47,6 +48,10 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ // Don't allow overlay windows.
+ getWindow().addSystemFlags(
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
mSendIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
// We need to touch the extras to unpack them so they get migrated to
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 0a052df..044b5ed 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -16,6 +16,7 @@
package com.android.systemui.animation;
+import android.util.MathUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
@@ -72,6 +73,27 @@
new PathInterpolator(0.9f, 0f, 0.7f, 1f);
/**
+ * Calculate the amount of overshoot using an exponential falloff function with desired
+ * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
+ * overshoot, retaining its acceleration.
+ *
+ * @param progress a progress value going from 0 to 1
+ * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
+ * value of the overall progress will be at 1.1.
+ * @param overshootStart the point in (0,1] where the result should reach 1
+ * @return the interpolated overshoot
+ */
+ public static float getOvershootInterpolation(float progress, float overshootAmount,
+ float overshootStart) {
+ if (overshootAmount == 0.0f || overshootStart == 0.0f) {
+ throw new IllegalArgumentException("Invalid values for overshoot");
+ }
+ float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
+ return MathUtils.max(0.0f,
+ (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
+ }
+
+ /**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction
*/
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 4d4c909..98ef9e2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -33,7 +33,7 @@
String ACTION = "com.android.systemui.action.PLUGIN_QS";
- int VERSION = 8;
+ int VERSION = 9;
String TAG = "QS";
@@ -50,8 +50,13 @@
void setListening(boolean listening);
boolean isShowingDetail();
void closeDetail();
- default void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {}
- void animateHeaderSlidingIn(long delay);
+
+ /**
+ * Set that we're currently pulse expanding
+ *
+ * @param pulseExpanding if we're currently expanding during pulsing
+ */
+ default void setPulseExpanding(boolean pulseExpanding) {}
void animateHeaderSlidingOut();
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
void setHeaderListening(boolean listening);
@@ -79,10 +84,23 @@
void setTranslateWhileExpanding(boolean shouldTranslate);
/**
+ * Set the amount of pixels we have currently dragged down if we're transitioning to the full
+ * shade. 0.0f means we're not transitioning yet.
+ */
+ default void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {}
+
+ /**
* A rounded corner clipping that makes QS feel as if it were behind everything.
*/
void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible);
+ /**
+ * @return if quick settings is fully collapsed currently
+ */
+ default boolean isFullyCollapsed() {
+ return true;
+ }
+
@ProvidesInterface(version = HeightListener.VERSION)
interface HeightListener {
int VERSION = 1;
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 7c5459c1..35eebac 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -81,5 +81,6 @@
android:layout_height="@dimen/notification_shelf_height"
android:layout_below="@id/keyguard_status_area"
android:paddingStart="@dimen/below_clock_padding_start_extra"
+ android:visibility="invisible"
/>
</com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res/color/media_player_solid_button_bg.xml b/packages/SystemUI/res/color/media_player_solid_button_bg.xml
new file mode 100644
index 0000000..96685ab
--- /dev/null
+++ b/packages/SystemUI/res/color/media_player_solid_button_bg.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentTertiary"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 95483f1..0dc1473 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -21,8 +21,7 @@
android:id="@+id/keyguard_bottom_area"
android:layout_height="match_parent"
android:layout_width="match_parent"
- android:outlineProvider="none"
- android:elevation="5dp" > <!-- Put it above the status bar header -->
+ android:outlineProvider="none" > <!-- Put it above the status bar header -->
<LinearLayout
android:id="@+id/keyguard_indication_area"
@@ -58,12 +57,6 @@
</LinearLayout>
- <FrameLayout
- android:id="@+id/preview_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </FrameLayout>
-
<com.android.systemui.statusbar.KeyguardAffordanceView
android:id="@+id/camera_button"
android:layout_height="@dimen/keyguard_affordance_height"
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index 9e67258..8c54e2c 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -75,7 +75,7 @@
android:id="@+id/media_logo1"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<ImageView
android:id="@+id/media_cover2"
@@ -91,7 +91,7 @@
android:id="@+id/media_logo2"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<ImageView
android:id="@+id/media_cover3"
@@ -107,7 +107,7 @@
android:id="@+id/media_logo3"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<ImageView
android:id="@+id/media_cover4"
@@ -123,7 +123,7 @@
android:id="@+id/media_logo4"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<ImageView
android:id="@+id/media_cover5"
@@ -139,7 +139,7 @@
android:id="@+id/media_logo5"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<ImageView
android:id="@+id/media_cover6"
@@ -155,7 +155,7 @@
android:id="@+id/media_logo6"
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size"
- style="@style/MediaPlayer.AppIcon.Recommendation" />
+ style="@style/MediaPlayer.AppIcon" />
<!-- Long press menu -->
<TextView
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 8dbbd4a..e999872 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -145,6 +145,7 @@
android:layout_width="@dimen/qs_seamless_icon_size"
android:layout_height="@dimen/qs_seamless_icon_size"
android:layout_gravity="center"
+ android:tint="?android:attr/textColorPrimary"
android:src="@*android:drawable/ic_media_seamless" />
<TextView
android:id="@+id/media_seamless_text"
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index 90214b7..f8175d4 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -13,37 +13,45 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<LinearLayout
+<!-- Have the wrapper frame layout match the parent height so that we get a larger touch area for
+ the chip. -->
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ongoing_call_chip"
android:layout_width="wrap_content"
- android:layout_height="@dimen/ongoing_appops_chip_height"
+ android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
- android:gravity="center_vertical"
- android:background="@drawable/ongoing_call_chip_bg"
- android:paddingStart="@dimen/ongoing_call_chip_side_padding"
- android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
- android:contentDescription="@string/ongoing_phone_call_content_description"
>
-
- <ImageView
- android:src="@*android:drawable/ic_phone"
- android:layout_width="@dimen/ongoing_call_chip_icon_size"
- android:layout_height="@dimen/ongoing_call_chip_icon_size"
- android:tint="?android:attr/colorPrimary"
- />
-
- <!-- TODO(b/183229367): The text in this view isn't quite centered within the chip. -->
- <com.android.systemui.statusbar.phone.ongoingcall.OngoingCallChronometer
- android:id="@+id/ongoing_call_chip_time"
+ <LinearLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:gravity="center|start"
- android:paddingStart="@dimen/ongoing_call_chip_icon_text_padding"
- android:textAppearance="@android:style/TextAppearance.Material.Small"
- android:fontFamily="@*android:string/config_headlineFontFamily"
- android:textColor="?android:attr/colorPrimary"
- />
+ android:layout_height="@dimen/ongoing_appops_chip_height"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:background="@drawable/ongoing_call_chip_bg"
+ android:paddingStart="@dimen/ongoing_call_chip_side_padding"
+ android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
+ android:contentDescription="@string/ongoing_phone_call_content_description"
+ android:minWidth="@dimen/min_clickable_item_size"
+ >
-</LinearLayout>
+ <ImageView
+ android:src="@*android:drawable/ic_phone"
+ android:layout_width="@dimen/ongoing_call_chip_icon_size"
+ android:layout_height="@dimen/ongoing_call_chip_icon_size"
+ android:tint="?android:attr/colorPrimary"
+ />
+
+ <com.android.systemui.statusbar.phone.ongoingcall.OngoingCallChronometer
+ android:id="@+id/ongoing_call_chip_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center|start"
+ android:paddingStart="@dimen/ongoing_call_chip_icon_text_padding"
+ android:textAppearance="@android:style/TextAppearance.Material.Small"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textColor="?android:attr/colorPrimary"
+ />
+
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index c521dc2..d4594d1 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -33,7 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:textAppearance="@style/TextAppearance.QS.Status"
+ android:textAppearance="@style/TextAppearance.QS.Status.Carriers"
android:textDirection="locale"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
diff --git a/packages/SystemUI/res/layout/qs_carrier_group.xml b/packages/SystemUI/res/layout/qs_carrier_group.xml
index 810c959..6e13ab9 100644
--- a/packages/SystemUI/res/layout/qs_carrier_group.xml
+++ b/packages/SystemUI/res/layout/qs_carrier_group.xml
@@ -32,7 +32,7 @@
android:minWidth="48dp"
android:minHeight="48dp"
android:gravity="center_vertical"
- android:textAppearance="@style/TextAppearance.QS.Status.NoCarrierText"
+ android:textAppearance="@style/TextAppearance.QS.Status.Carriers.NoCarrierText"
android:textDirection="locale"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
diff --git a/packages/SystemUI/res/layout/qs_customize_divider.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml
index 035f493..b4e3010 100644
--- a/packages/SystemUI/res/layout/qs_customize_divider.xml
+++ b/packages/SystemUI/res/layout/qs_customize_divider.xml
@@ -24,5 +24,5 @@
android:gravity="center"
android:paddingTop="24dp"
android:paddingBottom="24dp"
- android:textAppearance="@style/TextAppearance.QSEdit.Headers"
+ android:textAppearance="@style/TextAppearance.QSEdit"
android:text="@string/drag_to_add_tiles" />
diff --git a/packages/SystemUI/res/layout/qs_customize_header.xml b/packages/SystemUI/res/layout/qs_customize_header.xml
index 481561d..626d53a 100644
--- a/packages/SystemUI/res/layout/qs_customize_header.xml
+++ b/packages/SystemUI/res/layout/qs_customize_header.xml
@@ -22,5 +22,5 @@
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="@dimen/qs_customize_header_min_height"
- android:textAppearance="@style/TextAppearance.QSEdit.Headers"
+ android:textAppearance="@style/TextAppearance.QSEdit"
android:text="@string/drag_to_rearrange_tiles" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 609fc6d..0a9feb8 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -51,7 +51,7 @@
android:focusable="true"
android:gravity="center_vertical"
android:singleLine="true"
- android:textAppearance="@style/TextAppearance.QS.Build"
+ android:textAppearance="@style/TextAppearance.QS.Status.Build"
android:visibility="gone" />
<com.android.systemui.qs.PageIndicator
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index f4cb3b1..3543fd1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -37,6 +37,25 @@
android:layout_height="match_parent"
android:layout_width="match_parent" />
+ <include
+ layout="@layout/keyguard_bottom_area"
+ android:visibility="gone" />
+
+ <ViewStub
+ android:id="@+id/keyguard_user_switcher_stub"
+ android:layout="@layout/keyguard_user_switcher"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+
+ <include layout="@layout/status_bar_expanded_plugin_frame"/>
+
+ <include layout="@layout/dock_info_bottom_area_overlay" />
+
+ <com.android.keyguard.LockIconView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/lock_icon_view" />
+
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -49,6 +68,18 @@
layout="@layout/keyguard_status_view"
android:visibility="gone"/>
+ <com.android.systemui.scrim.ScrimView
+ android:id="@+id/scrim_notifications"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:importantForAccessibility="no"
+ systemui:ignoreRightInset="true"
+ systemui:layout_constraintStart_toStartOf="parent"
+ systemui:layout_constraintEnd_toEndOf="parent"
+ systemui:layout_constraintTop_toTopOf="parent"
+ systemui:layout_constraintBottom_toBottomOf="parent"
+ />
+
<include layout="@layout/dock_info_overlay" />
<FrameLayout
@@ -101,22 +132,9 @@
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
- <include layout="@layout/dock_info_bottom_area_overlay" />
-
- <include
- layout="@layout/keyguard_bottom_area"
- android:visibility="gone" />
-
- <ViewStub
- android:id="@+id/keyguard_user_switcher_stub"
- android:layout="@layout/keyguard_user_switcher"
- android:layout_height="match_parent"
- android:layout_width="match_parent" />
-
- <include layout="@layout/status_bar_expanded_plugin_frame"/>
-
- <com.android.keyguard.LockIconView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/lock_icon_view" />
+ <FrameLayout
+ android:id="@+id/preview_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </FrameLayout>
</com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index bea50e8..08284a0 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -51,14 +51,6 @@
sysui:ignoreRightInset="true"
/>
- <com.android.systemui.scrim.ScrimView
- android:id="@+id/scrim_notifications"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:importantForAccessibility="no"
- sysui:ignoreRightInset="true"
- />
-
<com.android.systemui.statusbar.LightRevealScrim
android:id="@+id/light_reveal_scrim"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 059cec7..3c936a0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Foon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Stembystand"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Beursie"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Ontsluit"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Toestel is gesluit"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Wat tans vir vingerafdruk"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"staaf"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"gaan by toestel in"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Oproep aan die gang"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ca97b18..c77dd57 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ካሜራ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ስልክ"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"የድምጽ እርዳታ"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"የኪስ ቦርሳ"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"ክፈት"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"መሣሪያ ተቆልፏል"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"የጣት አሻራን በመጠባበቅ ላይ"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ያረጋግጡ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"መሣሪያን ያስገቡ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"በመካሄድ ላይ የስልክ ጥሪ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 9a30ac2c..a3a00ed 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"الكاميرا"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"الهاتف"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"المساعد الصوتي"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"فتح القفل"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"الجهاز مُقفل."</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"في انتظار بصمة الإصبع"</string>
@@ -1174,6 +1176,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"المصادقة"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"الدخول إلى الجهاز"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 9d3eaae..0fba949 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"কেমেৰা"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ফ\'ন"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"কণ্ঠধ্বনিৰে সহায়"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"আনলক কৰক"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ডিভাইচটো লক হৈ আছে"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ফিংগাৰপ্ৰিণ্টৰ বাবে ৰৈ থকা হৈছে"</string>
@@ -289,11 +291,9 @@
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"ম’বাইল হটস্পট অফ কৰা হ’ল।"</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"ম’বাইল হটস্পট অন কৰা হ’ল।"</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"স্ক্ৰীণ কাষ্টিং বন্ধ কৰা হ’ল।"</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"কৰ্মস্থান ম’ড পজ হৈ আছে।"</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"কৰ্মস্থান ম\'ড অন হৈ আছে।"</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"কৰ্মস্থান ম’ড পজ হৈ আছে।"</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"কৰ্মস্থান ম\'ড অন কৰা হ’ল।"</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"ডেটা সঞ্চয়কাৰী সুবিধা অফ কৰা হ’ল।"</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"ডেটা সঞ্চয়কাৰী সুবিধা অন কৰা হ’ল।"</string>
@@ -412,8 +412,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সীমা"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সকীয়নি"</string>
<string name="quick_settings_work_mode_label" msgid="2754212289804324685">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
- <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
- <skip />
+ <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"পজ হৈ আছে"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ৰাতিৰ পোহৰ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূৰ্যাস্তত অন কৰক"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূৰ্যোদয়ৰ লৈকে"</string>
@@ -672,12 +671,10 @@
<string name="wallet_title" msgid="5369767670735827105">"ৱালেট"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"আটাইবোৰ দেখুৱাওক"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"পৰিশোধ কৰিবলৈ আনলক কৰক"</string>
- <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
- <skip />
+ <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"ছেট আপ কৰা হোৱা নাই"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
- <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
- <skip />
+ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্ৰীনৰ ছেটিং"</string>
<string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string>
<string name="add_tile" msgid="6239678623873086686">"টাইল যোগ দিয়ক"</string>
@@ -867,8 +864,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"অন"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"অফ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"উপলব্ধ নহয়"</string>
- <!-- no translation found for tile_disabled (373212051546573069) -->
- <skip />
+ <string name="tile_disabled" msgid="373212051546573069">"অক্ষম কৰা আছে"</string>
<string name="nav_bar" msgid="4642708685386136807">"নেভিগেশ্বন দণ্ড"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"বাওঁ বুটামৰ অতিৰিক্ত প্ৰকাৰ"</string>
@@ -1156,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"বিশ্বাসযোগ্যতা প্ৰমাণ কৰক"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইচ আনলক কৰক"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f04b5bd..7babf41 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Səs Yardımçısı"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Kiliddən çıxarın"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Cihaz kilidlənib"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Barmaq izi gözlənilir"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Ekran yayımı dayandırıldı."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"İş rejiminə pauza verilib."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"İş rejimi aktivdir."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"İş rejiminə pauza verilib."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"İş rejimi yanılıdır."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Trafikə qənaət edilmir."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Trafikə qənaət edilir."</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"doğrulayın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz daxil edin"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 0d1a4ad..4451304 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Otključajte"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čeka se otisak prsta"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"potvrdite identitet"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"unesite uređaj"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index c43ba46..26d4dff6e 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Тэлефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Галасавая дапамога"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Разблакiраваць"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Прылада заблакіравана"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Чаканне ўводу даных адбітка пальца"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Трансляцыя экрана спынена."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Працоўны рэжым прыпынены."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Рэжым працы ўкл."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"Працоўны рэжым прыпынены."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Рэжым працы ўключаны."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Эканомія трафіка адключана."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Эканомія трафіка ўключана."</string>
@@ -1163,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"правесці аўтэнтыфікацыю"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"вызначыць прыладу"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Каб адкрыць, скарыстайце адбітак пальца"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c80d984..9f4c899 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласова помощ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Отключване"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Устройството е заключено"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Изчаква се отпечатък"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"удостоверяване"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"вход в устройството"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index ee87769..66c03b2 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ক্যামেরা"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ফোন"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ভয়েস সহায়তা"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"আনলক করুন"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ডিভাইস লক করা আছে"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"আঙ্গুলের ছাপের জন্য অপেক্ষা করা হচ্ছে"</string>
@@ -289,8 +291,7 @@
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"মোবাইল হটস্পট বন্ধ হয়েছে।"</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"মোবাইল হটস্পট চালু হয়েছে।"</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"স্ক্রিন কাস্ট করা থেমেছে।"</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"\'অফিস\' মোড পজ করা আছে।"</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"কাজের মোড চালু আছে"</string>
<!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
<skip />
@@ -412,8 +413,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
<string name="quick_settings_work_mode_label" msgid="2754212289804324685">"কাজের প্রোফাইল"</string>
- <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
- <skip />
+ <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"পজ করা আছে"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"নাইট লাইট"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূর্যাস্তে চালু হবে"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূর্যোদয় পর্যন্ত"</string>
@@ -672,12 +672,10 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"সবকটি দেখুন"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"পেমেন্ট করতে ডিভাইস আনলক করুন"</string>
- <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
- <skip />
+ <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"সেট আপ করা নেই"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
- <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
- <skip />
+ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string>
<string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string>
<string name="add_tile" msgid="6239678623873086686">"টাইল যোগ করুন"</string>
@@ -867,8 +865,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"চালু আছে"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"বন্ধ আছে"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"উপলভ্য নয়"</string>
- <!-- no translation found for tile_disabled (373212051546573069) -->
- <skip />
+ <string name="tile_disabled" msgid="373212051546573069">"বন্ধ করা আছে"</string>
<string name="nav_bar" msgid="4642708685386136807">"নেভিগেশন বার"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"অতিরিক্ত বাঁদিকের বোতামের ধরণ"</string>
@@ -1156,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"যাচাই করিয়ে নিন"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইস আনলক করুন"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index e1ca309..e536e67 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Otključaj"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čeka se otisak prsta"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificiranje"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristup uređaju"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a39bf49..ec2a0a0 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Càmera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telèfon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistència per veu"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloqueja"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositiu bloquejat"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"S\'està esperant l\'empremta digital"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedir al dispositiu"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4868a03..db334f2 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotoaparát"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hlasová asistence"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Odemknout"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Zařízení uzamčeno"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čeká se na použití otisku"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ověříte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"zadáte zařízení"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ddcd5486..de4deff 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Taleassistent"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Lås op"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Enheden er låst"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Venter på fingeraftryk"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"godkende"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"få adgang til enheden"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 150bc25..e6334e0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonnummer"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Sprachassistent"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Entsperren"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Gerät gesperrt"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Auf Fingerabdruck wird gewartet"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authentifizieren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Eingeben des Geräts"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 4403f2d..8bc1765 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Φωτογραφική μηχανή"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Τηλέφωνο"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Φωνητική υποβοήθηση"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Ξεκλείδωμα"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Η συσκευή κλειδώθηκε"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Αναμονή για δακτυλικό αποτύπωμα"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"έλεγχος ταυτότητας"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"εισαγωγή συσκευής"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index f83468d..428a565 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Waiting for fingerprint"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index a7edecc..99ec519 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Waiting for fingerprint"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f83468d..428a565 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Waiting for fingerprint"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f83468d..428a565 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Waiting for fingerprint"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 1b34a61..11e32a759 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Waiting for fingerprint"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 31b25b3..1b0e816 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Cámara"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente voz"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Esperando huella dactilar"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella dactilar para abrir"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Se requiere de una autenticación. Toca el sensor de huellas dactilares para autenticarte."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 1f22cbd..33a8660 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Cámara"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente voz"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Esperando huella digital"</string>
@@ -1001,7 +1003,7 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"El modo Ahorro de batería se activará automáticamente cuando quede menos de un <xliff:g id="PERCENTAGE">%d</xliff:g> %% de batería."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ajustes"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entendido"</string>
- <string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar montículo de SysUI"</string>
<string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está usando tu <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que usan tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
@@ -1120,7 +1122,7 @@
<string name="timestamp" msgid="6577851592534538533">"Hace <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="less_than_timestamp" msgid="6598972791137724517">"Hace menos de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Hace más de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
- <string name="birthday_status" msgid="2596961629465396761">"Fecha de nacimiento"</string>
+ <string name="birthday_status" msgid="2596961629465396761">"Cumpleaños"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Es el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Cumpleaños en breve"</string>
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"Se acerca el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -1134,7 +1136,7 @@
<string name="audio_status" msgid="4237055636967709208">"Escuchando"</string>
<string name="game_status" msgid="1340694320630973259">"Reproduciendo"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amigos"</string>
- <string name="empty_status" msgid="5938893404951307749">"Charlemos esta noche"</string>
+ <string name="empty_status" msgid="5938893404951307749">"¿Hablamos luego?"</string>
<string name="status_before_loading" msgid="1500477307859631381">"El contenido se mostrará en breve"</string>
<string name="missed_call" msgid="4228016077700161689">"Llamada perdida"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticarte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acceder al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 80071ae..3d3a09b 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kaamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Häälabi"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Luku avamine"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Seade on lukustatud"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Sõrmejälje ootel"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentimiseks"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"seadmesse sisenemiseks"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Kasutage avamiseks sõrmejälge"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 3173ec6..eb2bde3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonoa"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ahots-laguntza"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desblokeatu"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Gailua blokeatuta dago"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Hatz-markaren zain"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"sartu gailuan"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b8dfb0b..aacf905 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"دوربین"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"تلفن"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"دستیار صوتی"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"باز کردن قفل"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"دستگاه قفل است"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"در انتظار اثر انگشت"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"اصالتسنجی کردن"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"وارد شدن به دستگاه"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"از اثر انگشت برای باز کردن قفل استفاده کنید"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"اصالتسنجی لازم است. برای اصالتسنجی، حسگر اثر انگشت را لمس کنید."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"تماس تلفنی درحال انجام"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bbe32dd..674a4be 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Puhelin"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ääniapuri"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Avaa lukitus"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Laite lukittu"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Odotetaan sormenjälkeä"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"todentaaksesi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"avataksesi laitteen"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 912e2a1..7bc9db9 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Appareil photo"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Téléphone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistance vocale"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Déverrouiller"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Appareil verrouillé"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"En attente de l\'empreinte digitale"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d055197..d7adaba 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Appareil photo"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Téléphoner"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistance vocale"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Déverrouiller"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Appareil verrouillé"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Attente de l\'empreinte digitale"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"s\'authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9147329..851c79a 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Cámara"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente de voz"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Agardando pola impresión dixital"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Detívose a emisión en pantalla."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Púxose en pausa o modo de traballo."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Modo de traballo activado."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"Púxose en pausa o modo de traballo."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Activouse o modo de traballo."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Desactivouse o aforro de datos."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Activouse o aforro de datos."</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"poñer o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa a impresión dixital para abrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 3ea9ebc..167817c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"કૅમેરો"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ફોન"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"વૉઇસ સહાય"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"અનલૉક કરો"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ડિવાઇસ લૉક કરેલું છે"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ફિંગરપ્રિન્ટની રાહ જોઈ રહ્યાં છીએ"</string>
@@ -473,14 +475,10 @@
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"સાવ\nશાંતિ"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"ફક્ત\nપ્રાધાન્યતા"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"ફક્ત\nએલાર્મ્સ"</string>
- <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
- <skip />
+ <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • વાયરલેસથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
+ <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ઝડપથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ધીમેથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"વપરાશકર્તાને સ્વિચ કરો, વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -1160,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ખાતરી કરો"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ડિવાઇસ અનલૉક કરો"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ae9a841..1160b9f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"कैमरा"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"फ़ोन"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज़ से डिवाइस का इस्तेमाल"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"अनलॉक करें"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"डिवाइस लॉक है"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"फ़िंगरप्रिंट का इंतज़ार हो रहा है"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"पुष्टि करें"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस की होम स्क्रीन पर जाएं"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 768b995..672b7db 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotoaparat"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Otključavanje"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čekanje na otisak prsta"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificirali"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristupili uređaju"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 6a64eff..b17d040 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hangsegéd"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Feloldás"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Az eszköz zárolva van"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Várakozás az ujjlenyomatra"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"a hitelesítéshez"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"eszköz megadásához"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ba8f838..61ed6e6 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Տեսախցիկ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Հեռախոս"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ձայնային հուշումներ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Ապակողպել"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Սարքը կողպված է"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Մատնահետքի սպասում"</string>
@@ -1113,7 +1115,7 @@
<string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Զրույցի վիջեթներ"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Հպեք զրույցին՝ այն հիմնական էկրանին ավելացնելու համար"</string>
- <string name="no_conversations_text" msgid="7362374212649891057">"Վերադարձեք այստեղ, երբ որևէ հաղորդագրություն ստանաք"</string>
+ <string name="no_conversations_text" msgid="7362374212649891057">"Վերադարձեք այստեղ, երբ հաղորդագրություններ ստանաք"</string>
<string name="priority_conversations" msgid="3967482288896653039">"Կարևոր զրույցներ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Վերջին հաղորդագրությունները"</string>
<string name="okay" msgid="6490552955618608554">"Եղավ"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"նույնականացնել"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"նշել սարքը"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b8abad2..880ca64 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telepon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Bantuan Suara"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Buka kunci"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Perangkat terkunci"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Menunggu sidik jari"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentikasi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"masukkan perangkat"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index afd4c05..eb7e4ec 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Myndavél"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Sími"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Raddaðstoð"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Taka úr lás"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Tækið er læst"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Bíður eftir fingrafari"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"auðkenna"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"opna tæki"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Opna með fingrafari"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5ce8293..600d8b7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotocamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Sblocca"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloccato"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"In attesa dell\'impronta"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"effettuare l\'autenticazione"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedere al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa l\'impronta per aprire"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticazione obbligatoria. Eseguila toccando il sensore di impronte digitali."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonata in corso"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f14c95a..c9be358 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"מצלמה"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"טלפון"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"האסיסטנט"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"ארנק"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"ביטול נעילה"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"המכשיר נעול"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"בהמתנה לטביעת אצבע"</string>
@@ -1162,6 +1163,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"הזנת מכשיר"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"מתקיימת שיחה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9ffc010..6465b44 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"カメラ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"音声アシスト"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ロック解除"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"デバイスはロックされています"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"指紋を待っています"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"認証"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"デバイスを入力"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"指紋を使って開いてください"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index afcd219..63205e3 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"კამერა"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ტელეფონი"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ხმოვანი დახმარება"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"განბლოკვა"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"მოწყობილობა ჩაკეტილია"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"თითის ანაბეჭდის მოლოდინში"</string>
@@ -1117,9 +1118,9 @@
<string name="priority_conversations" msgid="3967482288896653039">"პრიორიტეტული საუბრები"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ბოლო მიმოწერები"</string>
<string name="okay" msgid="6490552955618608554">"კარგი"</string>
- <string name="timestamp" msgid="6577851592534538533">"<xliff:g id="DURATION">%1$s</xliff:g>-ს წინ"</string>
+ <string name="timestamp" msgid="6577851592534538533">"<xliff:g id="DURATION">%1$s</xliff:g>ს წინ"</string>
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>-ზე ნაკლები ხნის წინ"</string>
- <string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>-ზე მეტი ხნის წინ"</string>
+ <string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>ზე მეტი ხნის წინ"</string>
<string name="birthday_status" msgid="2596961629465396761">"დაბადების დღე"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> დღეს იუბილარია"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"მალე დაბადების დღეა"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ავტორიზაცია"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"მოწყობილობის შეყვანა"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"მიმდინარე სატელეფონო ზარი"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d6e403d..bb5d51f 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Дауыс көмекшісі"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Бекітпесін ашу"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Құрылғы құлыпталды."</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Саусақ ізі күтілуде"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Экранды трансляциялау тоқтатылды."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Жұмыс режимі кідіртілді."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Жұмыс режимі қосулы."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"Жұмыс режимі кідіртілді."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Жұмыс режимі қосылды."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Трафикті үнемдеу режимі өшірілді."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Трафикті үнемдеу режимі қосылды."</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аутентификациялау"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"құрылғыны енгізу"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index a15ab8b..ed7bbe9 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ម៉ាស៊ីនថត"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ទូរសព្ទ"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ជំនួយសំឡេង"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ដោះសោ"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"បានចាក់សោឧបករណ៍"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"កំពុងរង់ចាំស្នាមម្រាមដៃ"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ផ្ទៀងផ្ទាត់"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"បញ្ចូលឧបករណ៍"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ប្រើស្នាមម្រាមដៃ ដើម្បីបើក"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 418130a..cef9e3f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ಕ್ಯಾಮರಾ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ಅನ್ಲಾಕ್"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ಗಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"ಸ್ಕ್ರೀನ್ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"ಕೆಲಸದ ಮೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಆಗಿದೆ."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"ಕೆಲಸದ ಮೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"ಡೇಟಾ ಸೇವರ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ದೃಢೀಕರಿಸಿ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2137478..ea45bd9 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"카메라"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"전화"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"음성 지원"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"잠금 해제"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"기기 잠김"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"지문 대기 중"</string>
@@ -1134,7 +1136,7 @@
<string name="audio_status" msgid="4237055636967709208">"듣는 중"</string>
<string name="game_status" msgid="1340694320630973259">"플레이 중"</string>
<string name="empty_user_name" msgid="3389155775773578300">"친구"</string>
- <string name="empty_status" msgid="5938893404951307749">"오늘 밤에 채팅"</string>
+ <string name="empty_status" msgid="5938893404951307749">"오늘 밤에 채팅하자!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"곧 콘텐츠가 표시됩니다."</string>
<string name="missed_call" msgid="4228016077700161689">"부재중 전화"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"인증"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"기기 입력"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 66e6ab0..d2db2c3 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Үн жардамчысы"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Кулпусун ачуу"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Түзмөк кулпуланды"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Манжаңызды сенсорго коюңуз"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Тышкы экранга чыгаруу аракети токтотулду."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Иштөө режими тындырылган."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Иштөө режими күйүк."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"Иштөө режими тындырылган."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Иштөө режими күйгүзүлдү."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Трафикти үнөмдөө режими өчүрүлдү."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Трафикти үнөмдөө режими күйгүзүлдү."</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аныктыгын текшерүү"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"түзмөккө кирүү"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index f9ac214..c162c54 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ກ້ອງ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ໂທລະສັບ"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ຊ່ວຍເຫຼືອທາງສຽງ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ປົດລັອກ"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ອຸປະກອນຖືກລັອກໄວ້"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ກຳລັງລໍຖ້າລາຍນິ້ວມື"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ພິສູດຢືນຢັນ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ເຂົ້າອຸປະກອນ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a87a927..3a9ccf0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotoaparatas"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonas"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Atrakinti"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Įrenginys užrakintas"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Laukiama piršto antspaudo"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"nustatytumėte tapatybę"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pasiektumėte įrenginį"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Naudokite kontrolinį kodą, kad atidarytumėte"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c1a3d60..c583cba 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Tālruņa numurs"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Balss palīgs"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Atbloķēt"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Ierīce ir bloķēta"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Tiek gaidīts pirksta nospiedums."</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"veiktu autentificēšanu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"izmantotu ierīci"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 198e733..d306e1f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласовна помош"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Отклучување"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Уредот е заклучен"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Се чека отпечаток"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"автентицирате"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"внесете уред"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 3e5b91d..750d834 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ക്യാമറ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ഫോണ്"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"വോയ്സ് സഹായം"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"അണ്ലോക്ക് ചെയ്യുക"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ഫിംഗർപ്രിന്റിനായി കാത്തിരിക്കുന്നു"</string>
@@ -1151,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"പരിശോധിച്ചുറപ്പിക്കുക"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ഉപകരണം നൽകുക"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"തുറക്കുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ea769ce..583b083 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камер"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Утас"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Дуут туслах"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Тайлах"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Төхөөрөмжийг түгжсэн"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Хурууны хээг хүлээж байна"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"баталгаажуулах"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"төхөөрөмж оруулах"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index f20d336..8fe5af0 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"कॅमेरा"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"व्हॉइस सहाय्य"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"अनलॉक करा"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"डिव्हाइस लॉक केले"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"फिंगरप्रिंटची प्रतीक्षा करत आहे"</string>
@@ -289,8 +291,7 @@
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"मोबाइल हॉटस्पॉट बंद केला."</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"मोबाइल हॉटस्पॉट सुरू केला."</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"स्क्रीन कास्ट करणे थांबले."</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"कार्य मोड थांबवला."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"कार्य मोड सुरू."</string>
<!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
<skip />
@@ -412,8 +413,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
<string name="quick_settings_work_mode_label" msgid="2754212289804324685">"कार्य प्रोफाइल"</string>
- <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
- <skip />
+ <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"थाबंवला"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"रात्रीचा प्रकाश"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"संध्याकाळी सुरू असते"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयापर्यंत"</string>
@@ -672,12 +672,10 @@
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"सर्व दाखवा"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"पैसे देण्यासाठी अनलॉक करा"</string>
- <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
- <skip />
+ <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"सेट केलेले नाही"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
- <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
- <skip />
+ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन सेटिंग्ज"</string>
<string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string>
<string name="add_tile" msgid="6239678623873086686">"टाइल जोडा"</string>
@@ -867,8 +865,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"सुरू"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"बंद"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध नाही"</string>
- <!-- no translation found for tile_disabled (373212051546573069) -->
- <skip />
+ <string name="tile_disabled" msgid="373212051546573069">"बंद केली"</string>
<string name="nav_bar" msgid="4642708685386136807">"नॅव्हिगेशन बार"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"अतिरिक्त डाव्या बटणाचा प्रकार"</string>
@@ -1156,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ऑथेंटिकेट करा"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिव्हाइस एंटर करा"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index c721ba5..791863a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Bantuan Suara"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Buka kunci"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Peranti dikunci"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Menunggu cap jari"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"sahkan"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"akses peranti"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan cap jari untuk membuka"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e565c7d..769c962 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ကင်မရာ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ဖုန်း"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"အသံ အကူအညီ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"သော့ဖွင့်ရန်"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"စက်ပစ္စည်းကို လော့ခ်ချထားသည်"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"လက်ဗွေကို စောင့်နေသည်"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"အထောက်အထားစိစစ်ရန်"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"စက်ပစ္စည်းသို့ ဝင်ရန်"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3700d04..c0aefb0 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonnummer"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Talehjelp"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Lås opp"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Enheten er låst"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Venger på fingeravtrykk"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentiser"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"åpne enheten"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående telefonsamtale"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b0afbcc..de375d3 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"क्यामेरा"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज सहायता"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"खोल्नुहोस्"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"यन्त्र लक गरिएको छ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"फिंगरप्रिन्ट कुर्दै"</string>
@@ -471,14 +473,10 @@
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"पूरै\nशान्त"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"प्राथमिकता \nमात्र"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"अलार्महरू \nमात्र"</string>
- <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
- <skip />
+ <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • तारविनै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
+ <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • छिटो चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • बिस्तारै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"प्रयोगकर्ता, हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> मा स्विच गर्नुहोस्"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -1155,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"प्रमाणित गर्नुहोस्"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index bd8e8ca..52b58b8 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefoon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Spraakassistent"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Ontgrendelen"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Apparaat vergrendeld"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Wachten op vingerafdruk"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"verifiëren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"apparaat opgeven"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om te openen"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3181a9a..20a66b3 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"କ୍ୟାମେରା"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ଫୋନ୍"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ଭଏସ୍ ସହାୟକ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ଟିପଚିହ୍ନ ପାଇଁ ଅପେକ୍ଷା କରୁଛି"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ପ୍ରମାଣୀକରଣ କରନ୍ତୁ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ଡିଭାଇସ୍ ବିଷୟରେ ସୂଚନା ଲେଖନ୍ତୁ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 15a3f1a..df2caea 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ਕੈਮਰਾ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ਫ਼ੋਨ ਕਰੋ"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ਅਣਲਾਕ ਕਰੋ"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ਡੀਵਾਈਸ ਲਾਕ ਹੈ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਉਡੀਕ ਹੋ ਰਹੀ ਹੈ"</string>
@@ -291,8 +293,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"ਸਕ੍ਰੀਨ ਜੋੜਨਾ ਬੰਦ ਹੋਇਆ।"</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"ਕਾਰਜ ਮੋਡ ਰੁਕਿਆ ਹੋਇਆ ਹੈ।"</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਹੈ।"</string>
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (6422896967647049692) -->
- <skip />
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="6422896967647049692">"ਕਾਰਜ ਮੋਡ ਰੁਕਿਆ ਹੋਇਆ ਹੈ।"</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"ਡਾਟਾ ਸੇਵਰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
@@ -1151,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ਡੀਵਾਈਸ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e035932..1a9c868 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Aparat"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asystent głosowy"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Odblokuj"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Urządzenie zablokowane"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Czekam na odcisk palca"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"uwierzytelnij"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"otwórz urządzenie"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e2a27f6..fa10f0f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Câmera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistência de voz"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Carteira"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Aguardando impressão digital"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c93170c..1723de6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Câmara"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telemóvel"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistente de voz"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"A aguardar a impressão digital…"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"entrar no dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilize a impressão digital para abrir"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e2a27f6..fa10f0f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Câmera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefone"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistência de voz"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Carteira"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Aguardando impressão digital"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 735ae55..1fb5514 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Cameră foto"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistent vocal"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Deblocați"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Dispozitiv blocat"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Se așteaptă amprenta"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Autentificați-vă"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Accesați dispozitivul"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosiți amprenta ca să deschideți"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 358e8c3..805e16e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон."</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Аудиоподсказки"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Разблокировать."</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Устройство заблокировано"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Отсканируйте отпечаток пальца"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"выполнить аутентификацию"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"указать устройство"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Используйте отпечаток пальца для входа."</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index dae509e..71e9077 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"කැමරාව"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"දුරකථනය"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"හඬ සහාය"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"පසුම්බිය"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"අඟුල අරින්න"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"උපාංගය අගුලු දමා ඇත"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ඇඟිලි සලකුණ සඳහා බලා සිටිමින්"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"සත්යාපනය කරන්න"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"උපාංගය ඇතුළු කරන්න"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"විවෘත කිරීමට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"සත්යාපනය අවශ්යයි. සත්යාපනය කිරීමට ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ක්රියාත්මක වන දුරකථන ඇමතුම"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0e0f6e5..79e1cfb 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotoaparát"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefón"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hlasový asistent"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Odomknúť"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Zariadenie je uzamknuté"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čaká sa na odtlačok prsta"</string>
@@ -1125,7 +1127,7 @@
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Miniaplikácie konverzácií"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Klepnite na konverzáciu a pridajte ju tak na plochu"</string>
- <string name="no_conversations_text" msgid="7362374212649891057">"Sem sa vráťte, keď dostanete nejaké správy"</string>
+ <string name="no_conversations_text" msgid="7362374212649891057">"Vráťte sa sem, až dostanete nejaké správy"</string>
<string name="priority_conversations" msgid="3967482288896653039">"Prioritné konverzácie"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedávne konverzácie"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1146,7 +1148,7 @@
<string name="audio_status" msgid="4237055636967709208">"Počúvam"</string>
<string name="game_status" msgid="1340694320630973259">"Hrá sa hra"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Priatelia"</string>
- <string name="empty_status" msgid="5938893404951307749">"Porozprávajme sa."</string>
+ <string name="empty_status" msgid="5938893404951307749">"Poďme sa rozprávať."</string>
<string name="status_before_loading" msgid="1500477307859631381">"Obsah sa čoskoro zobrazí"</string>
<string name="missed_call" msgid="4228016077700161689">"Zmeškaný hovor"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"overte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstúpte do zariadenia"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorte odtlačkom prsta"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 49c9982..6500e05 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Fotoaparat"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovni pomočnik"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Odkleni"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Naprava je zaklenjena."</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Čakanje na prstni odtis"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"preverjanje pristnosti"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstop v napravo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Odprite s prstnim odtisom"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 9153edc..9df3c98 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefoni"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ndihma zanore"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Shkyç"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Pajisja është e kyçur"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Në pritje për gjurmën e gishtit"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"për ta vërtetuar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"për të hyrë në pajisje"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index dbc3b90..055acfa 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласовна помоћ"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Откључајте"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Уређај је закључан"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Чека се отисак прста"</string>
@@ -1156,6 +1158,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"потврдите идентитет"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"унесите уређај"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Отворите помоћу отиска прста"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e2b94ee..a74b2ec 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Mobil"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Röstassistent"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Lås upp"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Enheten är låst"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Väntar på fingeravtryck"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentisera"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ange enhet"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9a7fa60..e60d575 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Simu"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Mapendekezo ya Sauti"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Fungua"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Kifaa kimefungwa"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Inasubiri alama ya kidole"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"thibitisha"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"weka kifaa"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Simu inayoendelea"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f4721a2..0b56d3b 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"கேமரா"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ஃபோன்"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"குரல் உதவி"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"திற"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"சாதனம் பூட்டப்பட்டுள்ளது"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"கைரேகைக்காகக் காத்திருக்கிறது"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"அங்கீகரி"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"சாதனத்தைத் திற"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index efa9840..7c797b7 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"కెమెరా"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ఫోన్"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"వాయిస్ అసిస్టెంట్"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"అన్లాక్ చేయి"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"పరికరం లాక్ చేయబడింది"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"వేలిముద్ర కోసం వేచి ఉంది"</string>
@@ -1151,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ప్రామాణీకరించండి"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"పరికరాన్ని ఎంటర్ చేయండి"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 96e837a..e7c20d2 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"กล้องถ่ายรูป"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"โทรศัพท์"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ตัวช่วยเสียง"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"ปลดล็อก"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"อุปกรณ์ถูกล็อก"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"กำลังรอลายนิ้วมือ"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ตรวจสอบสิทธิ์"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"เข้าถึงอุปกรณ์"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ใช้ลายนิ้วมือเพื่อเปิด"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7887883..d94e7a6 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Camera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telepono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"I-unlock"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Naka-lock ang device"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Naghihintay ng fingerprint"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"i-authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ilagay ang device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gamitin ang fingerprint para buksan"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 75dbb08..d5185fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Sesli Yardım"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Cüzdan"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Kilidi aç"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Cihaz kilitlendi"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Parmak izi bekleniyor"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"kimlik doğrulaması yapın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz girin"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Devam eden telefon görüşmesi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5f69f55..df9c5bf 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Камера"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Номер телефону"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Голосові підказки"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Розблокувати"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Пристрій заблоковано"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Очікується відбиток пальця"</string>
@@ -1162,6 +1164,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"пройти автентифікацію"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 88b8c77..be8fafb 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"کیمرا"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"فون"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"صوتی معاون"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"غیر مقفل کریں"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"آلہ مقفل کر دیا گیا"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"فنگر پرنٹ کا انتظار ہے"</string>
@@ -1151,6 +1153,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"تصدیق کریں"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"آلہ درج کریں"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 274b7a3..131373c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Kamera"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ovozli yordam"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Qulfdan chiqarish"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Qurilma qulflandi"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Barmoq izingizni skanerlang"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatsiya"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"qurilmani ochish"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ochish uchun barmoq izidan foydalaning"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Haqiqiylikni tekshirish talab etiladi. Autentifikatsiya uchun barmoq izi skaneriga tegining."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Joriy telefon chaqiruvi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 359fe54..7a381c5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Máy ảnh"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Điện thoại"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Trợ lý thoại"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"Mở khóa"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Đã khóa thiết bị"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Đang chờ vân tay"</string>
@@ -1134,7 +1136,7 @@
<string name="audio_status" msgid="4237055636967709208">"Đang nghe"</string>
<string name="game_status" msgid="1340694320630973259">"Đang chơi"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Bạn bè"</string>
- <string name="empty_status" msgid="5938893404951307749">"Cùng trò chuyện tối nay nhé!"</string>
+ <string name="empty_status" msgid="5938893404951307749">"Tối nay nói chuyện nhé!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"Nội dung sẽ sớm hiển thị"</string>
<string name="missed_call" msgid="4228016077700161689">"Cuộc gọi nhỡ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Hơn <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"xác thực"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"truy cập thiết bị"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index f3760ab..0f162be 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"相机"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"电话"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"语音助理"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"解锁"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"设备已锁定"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"正在等待提供指纹"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"身份验证"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"进入设备"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 081ec16..cd02e78 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"相機"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"語音助手"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"解鎖"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"裝置已上鎖"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"正在等待指紋"</string>
@@ -470,10 +472,10 @@
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"完全\n靜音"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"僅限\n優先"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"僅限\n鬧鐘"</string>
- <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在無線充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後完成充電"</string>
- <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後完成充電"</string>
- <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在快速充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後完成充電"</string>
- <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在慢速充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後完成充電"</string>
+ <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 無線充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
+ <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 快速充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"目前的使用者是 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -1113,7 +1115,7 @@
<string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"對話小工具"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"輕按對話即可新增至主畫面"</string>
- <string name="no_conversations_text" msgid="7362374212649891057">"待你收到一些訊息後再回來查看"</string>
+ <string name="no_conversations_text" msgid="7362374212649891057">"等你收到一些訊息後再回來查看吧"</string>
<string name="priority_conversations" msgid="3967482288896653039">"優先對話"</string>
<string name="recent_conversations" msgid="8531874684782574622">"最近的對話"</string>
<string name="okay" msgid="6490552955618608554">"確定"</string>
@@ -1134,7 +1136,7 @@
<string name="audio_status" msgid="4237055636967709208">"正在聽取音訊"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩遊戲"</string>
<string name="empty_user_name" msgid="3389155775773578300">"朋友"</string>
- <string name="empty_status" msgid="5938893404951307749">"今晚聊天吧!"</string>
+ <string name="empty_status" msgid="5938893404951307749">"今晚傾下偈啦!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"即將顯示內容"</string>
<string name="missed_call" msgid="4228016077700161689">"未接來電"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 66a5678..043cf43 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -136,6 +136,8 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"相機"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"語音小幫手"</string>
+ <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
+ <skip />
<string name="accessibility_unlock_button" msgid="122785427241471085">"解除鎖定"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"裝置已鎖定"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"正在等候指紋"</string>
@@ -1150,6 +1152,8 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
+ <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
+ <skip />
<!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 0fdc7d1..a444cd0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -136,6 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"Ikhamela"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"Ifoni"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Isisekeli sezwi"</string>
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"I-wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Vula"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Idivayisi ikhiyiwe"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Ilindele izigxivizo zeminwe"</string>
@@ -1150,6 +1151,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"gunyaza"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"faka idivayisi"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string>
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ikholi yefoni eqhubekayo"</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 87a669f..e7d714e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1409,6 +1409,26 @@
<dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
+ <!-- Delay after which the media will start transitioning to the full shade on
+ the lockscreen -->
+ <dimen name="lockscreen_shade_media_transition_start_delay">40dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order for qs to fully transition to the
+ shade -->
+ <dimen name="lockscreen_shade_qs_transition_distance">200dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order for scrim to fully transition to
+ the shade (in alpha) -->
+ <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+
+ <!-- Extra inset for the notifications when accounting for media during the lockscreen to
+ shade transition to compensate for the disappearing media -->
+ <dimen name="lockscreen_shade_transition_extra_media_inset">-48dp</dimen>
+
+ <!-- Maximum overshoot for the topPadding of notifications when transitioning to the full
+ shade -->
+ <dimen name="lockscreen_shade_max_top_overshoot">32dp</dimen>
+
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
<dimen name="people_space_messages_count_radius">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 427ede5..36a1bb3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -691,10 +691,6 @@
<string name="accessibility_quick_settings_hotspot_changed_on">Mobile hotspot turned on.</string>
<!-- Announcement made when the screen stopped casting (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_casting_turned_off">Screen casting stopped.</string>
- <!-- Content description of the work mode title in quick settings when off (not shown on the screen). Paused is used as an adjective [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_work_mode_off">Work mode paused.</string>
- <!-- Content description of the work mode title in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_work_mode_on">Work mode on.</string>
<!-- Announcement made when the work mode changes to off (not shown on the screen). Paused is used as a verb. [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_work_mode_changed_off">Work mode paused.</string>
<!-- Announcement made when the work mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -953,11 +949,9 @@
<string name="quick_settings_cellular_detail_data_warning"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> warning</string>
<!-- QuickSettings: This string is in the easy-to-view settings that a user can pull down from
the top of their phone's screen. This is a label for a toggle to turn the work profile on and
- off. "Work profile" means a separate profile on a user's phone that's specifically for their
+ off. This means a separate profile on a user's phone that's specifically for their
work apps and managed by their company. "Work" is used as an adjective. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_work_mode_label">Work profile</string>
- <!-- QuickSettings: Secondary label for work mode tile when it's off. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_work_mode_paused">Paused</string>
+ <string name="quick_settings_work_mode_label">Work apps</string>
<!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
<string name="quick_settings_night_display_label">Night Light</string>
<!-- QuickSettings: Secondary text for when the Night Light will be enabled at sunset. [CHAR LIMIT=20] -->
@@ -2724,15 +2718,8 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle">toggle</string>
<!-- Device Controls strings -->
- <!-- Device Controls empty state, title [CHAR LIMIT=30] -->
- <string name="quick_controls_title">Device controls</string>
- <!-- Device Controls empty state, subtitle [CHAR LIMIT=100] -->
- <string name="quick_controls_subtitle">Add controls for your connected devices</string>
-
- <!-- Device Controls setup, title [CHAR LIMIT=50] -->
- <string name="quick_controls_setup_title">Set up device controls</string>
- <!-- Device Controls setup, subtitle [CHAR LIMIT=100] -->
- <string name="quick_controls_setup_subtitle">Hold the Power button to access your controls</string>
+ <!-- Device Controls, Quick Settings tile title [CHAR LIMIT=30] -->
+ <string name="quick_controls_title">Home controls</string>
<!-- Controls management providers screen title [CHAR LIMIT=60]-->
<string name="controls_providers_title">Choose app to add controls</string>
@@ -2761,7 +2748,7 @@
<!-- Controls management controls screen default title [CHAR LIMIT=30] -->
<string name="controls_favorite_default_title">Controls</string>
<!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
- <string name="controls_favorite_subtitle">Choose controls to access from the power menu</string>
+ <string name="controls_favorite_subtitle">Choose controls to access from Quick Settings</string>
<!-- Controls management editing screen, user direction for rearranging controls [CHAR LIMIT=NONE] -->
<string name="controls_favorite_rearrange">Hold & drag to rearrange controls</string>
@@ -2853,7 +2840,7 @@
<!-- Stateless control message informing the user that a routine has started [CHAR_LIMIT=30] -->
<string name="controls_in_progress">In progress</string>
<!-- Tooltip informing user where the recently added controls are [CHAR_LIMIT=100] -->
- <string name="controls_added_tooltip">Hold Power button to see new controls</string>
+ <string name="controls_added_tooltip">Open Quick Settings to see new controls</string>
<!-- Controls menu, add [CHAR_LIMIT=30] -->
<string name="controls_menu_add">Add controls</string>
@@ -2952,8 +2939,6 @@
[CHAR LIMIT=NONE] -->
<string name="battery_state_unknown_notification_text">Tap for more information</string>
- <string name="qs_tile_label_fontFamily" translatable="false">@*android:string/config_headlineFontFamilyMedium</string>
-
<!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] -->
<string name="qs_alarm_tile_no_alarm">No alarm set</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index df68dbd..9ce7589 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -197,12 +197,13 @@
<style name="TextAppearance.QS.TileLabel">
<item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:fontFamily">@string/qs_tile_label_fontFamily</item>
+ <item name="android:letterSpacing">0.01</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
</style>
<style name="TextAppearance.QS.TileLabel.Secondary">
- <item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
<style name="TextAppearance.QS.UserSwitcher">
@@ -221,11 +222,6 @@
<item name="android:textSize">@dimen/celltile_rat_type_size</item>
</style>
- <style name="TextAppearance.QS.SecurityFooter">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textSize">@dimen/qs_tile_text_size</item>
- </style>
-
<style name="TextAppearance.QS.Status">
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
@@ -234,14 +230,22 @@
<item name="android:lineHeight">20sp</item>
</style>
- <style name="TextAppearance.QS.Status.NoCarrierText">
+ <style name="TextAppearance.QS.SecurityFooter" parent="@style/TextAppearance.QS.Status">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.QS.Build">
+ <style name="TextAppearance.QS.Status.Carriers">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ </style>
+
+ <style name="TextAppearance.QS.Status.Carriers.NoCarrierText">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.QS.Status.Build">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.DeviceManagementDialog">
@@ -603,11 +607,12 @@
parent="@*android:style/TextAppearance.DeviceDefault.Notification.Info">
</style>
- <style name="TextAppearance.QSEdit.Headers"
- parent="@*android:style/TextAppearance.DeviceDefault.Body2">
- <item name="android:textSize">11sp</item>
+ <style name="TextAppearance.QSEdit" >
+ <item name="android:textSize">14sp</item>
+ <item name="android:letterSpacing">0.01</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textAllCaps">true</item>
</style>
<style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
@@ -649,19 +654,14 @@
</style>
<style name="MediaPlayer.SolidButton">
- <item name="android:backgroundTint">?android:attr/colorAccent</item>
+ <item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
<item name="android:tint">?android:attr/colorPrimary</item>
- <item name="android:textColor">?android:attr/colorPrimary</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="MediaPlayer.AppIcon">
<item name="android:background">@drawable/qs_media_icon_background</item>
- <item name="android:backgroundTint">?android:attr/colorPrimary</item>
- <item name="android:tint">?android:attr/colorAccent</item>
- </style>
-
- <style name="MediaPlayer.AppIcon.Recommendation" parent="MediaPlayer.AppIcon">
- <item name="android:tint">@color/transparent</item>
+ <item name="android:backgroundTint">?android:attr/textColorPrimary</item>
</style>
<style name="MediaPlayer.Album">
diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
index bdb8c04..a03a1d3 100644
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_collapsed.xml
@@ -69,6 +69,7 @@
android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
/>
<!-- Song name -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 1e98f86..f61cadb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -134,5 +134,8 @@
*/
void onBackPressed() = 44;
- // Next id = 45
+ /** Sets home rotation enabled. */
+ void setHomeRotationEnabled(boolean enabled) = 45;
+
+ // Next id = 46
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index bec9220..d40b94c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -40,6 +40,8 @@
InteractionJankMonitor.CUJ_LAUNCHER_OPEN_ALL_APPS;
public static final int CUJ_ALL_APPS_SCROLL =
InteractionJankMonitor.CUJ_LAUNCHER_ALL_APPS_SCROLL;
+ public static final int CUJ_APP_LAUNCH_FROM_WIDGET =
+ InteractionJankMonitor.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
@@ -47,6 +49,7 @@
CUJ_APP_CLOSE_TO_HOME,
CUJ_APP_CLOSE_TO_PIP,
CUJ_QUICK_SWITCH,
+ CUJ_APP_LAUNCH_FROM_WIDGET,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 1cc488f..700ec49 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -19,6 +19,7 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
+import android.view.SurfaceControl;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
@@ -76,11 +77,13 @@
* updated accordingly. This should be called before `finish`
* @param taskId Task id of the Activity in PiP mode.
* @param finishTransaction leash operations for the final transform.
+ * @param overlay the surface control for an overlay being shown above the pip (can be null)
*/
public void setFinishTaskTransaction(int taskId,
- PictureInPictureSurfaceTransaction finishTransaction) {
+ PictureInPictureSurfaceTransaction finishTransaction,
+ SurfaceControl overlay) {
try {
- mAnimationController.setFinishTaskTransaction(taskId, finishTransaction);
+ mAnimationController.setFinishTaskTransaction(taskId, finishTransaction, overlay);
} catch (RemoteException e) {
Log.d(TAG, "Failed to set finish task bounds", e);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 5708855..1729997a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -236,9 +236,9 @@
}
@Override public void setFinishTaskTransaction(int taskId,
- PictureInPictureSurfaceTransaction finishTransaction) {
+ PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
if (mWrapped != null) {
- mWrapped.setFinishTaskTransaction(taskId, finishTransaction);
+ mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 4b9bf8c..e6ec04b 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -37,7 +37,8 @@
import java.util.TimeZone;
/**
- * Controller for an AnimatableClockView. Instantiated by {@link KeyguardClockSwitchController}.
+ * Controller for an AnimatableClockView on the keyguard. Instantiated by
+ * {@link KeyguardClockSwitchController}.
*/
public class AnimatableClockController extends ViewController<AnimatableClockView> {
private static final int FORMAT_NUMBER = 1234567890;
@@ -46,6 +47,7 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mBypassController;
+ private final BatteryController mBatteryController;
private final int mDozingColor = Color.WHITE;
private int mLockScreenColor;
@@ -53,6 +55,7 @@
private boolean mIsCharging;
private float mDozeAmount;
private Locale mLocale;
+ private boolean mAttached; // if keyguard isn't showing, mAttached = false
private final NumberFormat mBurmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"));
private final String mBurmeseNumerals;
@@ -73,44 +76,47 @@
mBroadcastDispatcher = broadcastDispatcher;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBypassController = bypassController;
+ mBatteryController = batteryController;
mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER);
mBurmeseLineSpacing = getContext().getResources().getFloat(
R.dimen.keyguard_clock_line_spacing_scale_burmese);
mDefaultLineSpacing = getContext().getResources().getFloat(
R.dimen.keyguard_clock_line_spacing_scale);
-
- batteryController.addCallback(new BatteryController.BatteryStateChangeCallback() {
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- if (!mIsCharging && charging) {
- mView.animateCharge(mIsDozing);
- }
- mIsCharging = charging;
- }
- });
}
- private BroadcastReceiver mLocaleBroadcastReceiver = new BroadcastReceiver() {
+ private final BatteryController.BatteryStateChangeCallback mBatteryCallback =
+ new BatteryController.BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ if (!mIsCharging && charging) {
+ mView.animateCharge(mIsDozing);
+ }
+ mIsCharging = charging;
+ }
+ };
+
+ private final BroadcastReceiver mLocaleBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateLocale();
}
};
- @Override
- protected void onViewAttached() {
- updateLocale();
- mBroadcastDispatcher.registerReceiver(mLocaleBroadcastReceiver,
- new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
- mStatusBarStateController.addCallback(mStatusBarStateListener);
- mIsDozing = mStatusBarStateController.isDozing();
- mDozeAmount = mStatusBarStateController.getDozeAmount();
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
-
- refreshTime();
- initColors();
- }
+ private final KeyguardUpdateMonitorCallback mKeyguardPersistentCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ // call attached/detached methods on visibility changes. benefits include:
+ // - no animations when keyguard/clock view aren't visible
+ // - resets state when keyguard is visible again (ie: font weight)
+ if (showing) {
+ onViewAttached();
+ } else {
+ onViewDetached();
+ }
+ }
+ };
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -125,10 +131,41 @@
};
@Override
+ protected void onViewAttached() {
+ if (mAttached) {
+ return;
+ }
+ mAttached = true;
+ updateLocale();
+ mBroadcastDispatcher.registerReceiver(mLocaleBroadcastReceiver,
+ new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mIsDozing = mStatusBarStateController.isDozing();
+ mDozeAmount = mStatusBarStateController.getDozeAmount();
+ mBatteryController.addCallback(mBatteryCallback);
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardPersistentCallback);
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardPersistentCallback);
+
+ refreshTime();
+ initColors();
+ }
+
+ @Override
protected void onViewDetached() {
+ if (!mAttached) {
+ return;
+ }
+
+ mAttached = false;
mBroadcastDispatcher.unregisterReceiver(mLocaleBroadcastReceiver);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+ mBatteryController.removeCallback(mBatteryCallback);
+ if (!mView.isAttachedToWindow()) {
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardPersistentCallback);
+ }
}
/** Animate the clock appearance */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 4245fbc..aa7f9a2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -124,16 +124,6 @@
@Override
public void onInit() {
mKeyguardSliceViewController.init();
- }
-
- @Override
- protected void onViewAttached() {
- if (CUSTOM_CLOCKS_ENABLED) {
- mClockManager.addOnClockChangedListener(mClockChangedListener);
- }
- mColorExtractor.addOnColorsChangedListener(mColorsListener);
- mView.updateColors(getGradientColors());
- updateAodIcons();
mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
@@ -157,6 +147,16 @@
mKeyguardUpdateMonitor,
mBypassController);
mLargeClockViewController.init();
+ }
+
+ @Override
+ protected void onViewAttached() {
+ if (CUSTOM_CLOCKS_ENABLED) {
+ mClockManager.addOnClockChangedListener(mClockChangedListener);
+ }
+ mColorExtractor.addOnColorsChangedListener(mColorsListener);
+ mView.updateColors(getGradientColors());
+ updateAodIcons();
if (mSmartspaceController.isEnabled()) {
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
@@ -259,6 +259,9 @@
mClockViewController.refreshTime();
mLargeClockViewController.refreshTime();
}
+ if (mSmartspaceController != null) {
+ mSmartspaceController.requestSmartspaceUpdate();
+ }
mView.refresh();
}
@@ -307,8 +310,6 @@
NotificationIconContainer nic = (NotificationIconContainer)
mView.findViewById(
com.android.systemui.R.id.left_aligned_notification_icon_container);
-
- // alt icon area is set in KeyguardClockSwitchController
mNotificationIconAreaController.setupAodIcons(nic);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index d06c8bc..3ebd652 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -481,7 +481,7 @@
if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)
&& resources.getBoolean(
- com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
gravity = resources.getInteger(
R.integer.keyguard_host_view_one_handed_gravity);
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 54ecf95..ca4d73b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -278,7 +278,7 @@
private boolean canUseOneHandedBouncer() {
// Is it enabled?
if (!getResources().getBoolean(
- com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 3a3f2fc..388c085 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -198,6 +198,13 @@
}
/**
+ * @return {@code true} if we are currently animating the screen off from unlock
+ */
+ public boolean isAnimatingScreenOffFromUnlocked() {
+ return mKeyguardVisibilityHelper.isAnimatingScreenOffFromUnlocked();
+ }
+
+ /**
* Set the visibility of the keyguard status view based on some new state.
*/
public void setKeyguardStatusViewVisibility(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 64bc77f..44df02a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -252,7 +252,6 @@
@Override
public void onStateChanged(int newState) {
mStatusBarState = newState;
- updateBiometricListeningState();
}
@Override
@@ -2199,7 +2198,7 @@
&& !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
&& !mKeyguardGoingAway && mBiometricEnabledForUser.get(user) && !mLockIconPressed
&& strongAuthAllowsScanning && mIsPrimaryUser
- && !mSecureCameraLaunched;
+ && (!mSecureCameraLaunched || mOccludingAppRequestingFace);
// Aggregate relevant fields for debug logging.
if (DEBUG_FACE || DEBUG_SPEW) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 6aca5a7..b6a58dc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -22,6 +22,9 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -37,6 +40,8 @@
private final DozeParameters mDozeParameters;
private boolean mKeyguardViewVisibilityAnimating;
private boolean mLastOccludedState = false;
+ private boolean mAnimatingScreenOff;
+ private final AnimationProperties mAnimationProperties = new AnimationProperties();
public KeyguardVisibilityHelper(View view, KeyguardStateController keyguardStateController,
DozeParameters dozeParameters) {
@@ -89,12 +94,21 @@
} else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
mKeyguardViewVisibilityAnimating = true;
+ float target = mView.getY() - mView.getHeight() * 0.05f;
+ int delay = 0;
+ int duration = 125;
+ // We animate the Y properly separately using the PropertyAnimator, as the panel
+ // view als needs to update the end position.
+ mAnimationProperties.setDuration(duration).setDelay(delay);
+ PropertyAnimator.cancelAnimation(mView, AnimatableProperty.Y);
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, target,
+ mAnimationProperties,
+ true /* animate */);
mView.animate()
.alpha(0)
- .translationYBy(-mView.getHeight() * 0.05f)
.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
- .setDuration(125)
- .setStartDelay(0)
+ .setDuration(duration)
+ .setStartDelay(delay)
.withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable)
.start();
} else if (mLastOccludedState && !isOccluded) {
@@ -110,20 +124,30 @@
.start();
} else if (mDozeParameters.shouldControlUnlockedScreenOff()) {
mKeyguardViewVisibilityAnimating = true;
+ mAnimatingScreenOff = true;
mView.setVisibility(View.VISIBLE);
mView.setAlpha(0f);
+ float currentY = mView.getY();
+ mView.setY(currentY - mView.getHeight() * 0.1f);
+ int duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
+ int delay = (int) (duration * .6f);
+ // We animate the Y properly separately using the PropertyAnimator, as the panel
+ // view als needs to update the end position.
+ mAnimationProperties.setDuration(duration).setDelay(delay);
+ PropertyAnimator.cancelAnimation(mView, AnimatableProperty.Y);
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, currentY,
+ mAnimationProperties,
+ true /* animate */);
- float curTranslationY = mView.getTranslationY();
- mView.setTranslationY(curTranslationY - mView.getHeight() * 0.1f);
mView.animate()
- .setStartDelay((int) (StackStateAnimator.ANIMATION_DURATION_WAKEUP * .6f))
- .setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP)
+ .setStartDelay(delay)
+ .setDuration(duration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1f)
- .translationY(curTranslationY)
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
.start();
+
} else {
mView.setVisibility(View.VISIBLE);
mView.setAlpha(1f);
@@ -148,5 +172,13 @@
private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> {
mKeyguardViewVisibilityAnimating = false;
+ mAnimatingScreenOff = false;
};
+
+ /**
+ * @return {@code true} if we are currently animating the screen off from unlock
+ */
+ public boolean isAnimatingScreenOffFromUnlocked() {
+ return mAnimatingScreenOff;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index b367bdf..7127444 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -145,7 +145,13 @@
final boolean hasUdfps = mAuthController.getUdfpsSensorLocation() != null;
mHasUdfpsOrFaceAuthFeatures = hasFaceAuth || hasUdfps;
if (!mHasUdfpsOrFaceAuthFeatures) {
- ((ViewGroup) mView.getParent()).removeView(mView);
+ // Posting since removing a view in the middle of onAttach can lead to a crash in the
+ // iteration loop when the view isn't last
+ mView.setVisibility(View.GONE);
+ mView.post(() -> {
+ mView.setVisibility(View.VISIBLE);
+ ((ViewGroup) mView.getParent()).removeView(mView);
+ });
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 55f3981..e85bd88 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -544,9 +544,8 @@
final int currentX = (int) event.getX();
final int currentY = (int) event.getY();
- final int menuHalfWidth = getLayoutWidth() / 2;
final Rect touchDelegateBounds =
- new Rect(mMargin, mMargin, mMargin + menuHalfWidth, mMargin + getLayoutHeight());
+ new Rect(mMargin, mMargin, mMargin + getLayoutWidth(), mMargin + getLayoutHeight());
if (action == MotionEvent.ACTION_DOWN
&& touchDelegateBounds.contains(currentX, currentY)) {
mIsDownInEnlargedTouchArea = true;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java
index 1abf559..3085854 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java
@@ -77,7 +77,6 @@
mAnchorView = anchorView;
mCurrentLayoutParams = createDefaultLayoutParams();
- updateDimensions();
initViews();
}
@@ -85,14 +84,8 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- updateDimensions();
- updateTextView();
-
mAnchorView.onConfigurationChanged(newConfig);
- final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
- updateArrowWith(anchorViewLocation);
- updateWidthWith(anchorViewLocation);
- updateLocationWith(anchorViewLocation);
+ updateTooltipView();
mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
}
@@ -129,10 +122,7 @@
}
mIsShowing = true;
- final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
- updateArrowWith(anchorViewLocation);
- updateWidthWith(anchorViewLocation);
- updateLocationWith(anchorViewLocation);
+ updateTooltipView();
mWindowManager.addView(this, mCurrentLayoutParams);
}
@@ -207,6 +197,16 @@
R.dimen.accessibility_floating_tooltip_text_corner_radius);
}
+ private void updateTooltipView() {
+ updateDimensions();
+ updateTextView();
+
+ final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
+ updateArrowWith(anchorViewLocation);
+ updateWidthWith(anchorViewLocation);
+ updateLocationWith(anchorViewLocation);
+ }
+
private void updateTextView() {
mTextView.setTextSize(COMPLEX_UNIT_PX, mFontSize);
mTextView.setPadding(mTextViewPadding, mTextViewPadding, mTextViewPadding,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e8300b9..3075617 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -630,6 +630,14 @@
animation.init();
mView.setAnimationViewController(animation);
+ // This view overlaps the sensor area, so prevent it from being selectable
+ // during a11y.
+ if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
+ || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
+ mView.setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ }
+
mWindowManager.addView(mView, computeLayoutParams(animation));
mAccessibilityManager.addTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 521c495..470fb8c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -26,6 +26,7 @@
import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
+import android.view.accessibility.AccessibilityManager;
import java.util.ArrayList;
import java.util.List;
@@ -53,6 +54,7 @@
@NonNull private final Context mContext;
// IUdfpsOverlayController reason
private final int mEnrollReason;
+ private final boolean mAccessibilityEnabled;
@NonNull private final List<PointF> mGuidedEnrollmentPoints;
private int mTotalSteps = -1;
@@ -67,6 +69,10 @@
public UdfpsEnrollHelper(@NonNull Context context, int reason) {
mContext = context;
mEnrollReason = reason;
+
+ final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ mAccessibilityEnabled = am.isEnabled();
+
mGuidedEnrollmentPoints = new ArrayList<>();
// Number of pixels per mm
@@ -148,6 +154,8 @@
boolean isCenterEnrollmentComplete() {
if (mTotalSteps == -1 || mRemainingSteps == -1) {
return false;
+ } else if (mAccessibilityEnabled) {
+ return false;
}
final int stepsEnrolled = mTotalSteps - mRemainingSteps;
return stepsEnrolled >= NUM_CENTER_TOUCHES;
@@ -155,6 +163,10 @@
@NonNull
PointF getNextGuidedEnrollmentPoint() {
+ if (mAccessibilityEnabled) {
+ return new PointF(0f, 0f);
+ }
+
float scale = SCALE;
if (Build.IS_ENG || Build.IS_USERDEBUG) {
scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 52576a7..804e2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -148,7 +148,7 @@
/**
* Animates in the bg protection circle behind the fp icon to highlight the icon.
*/
- void animateUdfpsBouncer() {
+ void animateUdfpsBouncer(Runnable onEndAnimation) {
if (mBgProtection.getVisibility() == View.VISIBLE && mBgProtection.getAlpha() == 1f) {
// already fully highlighted, don't re-animate
return;
@@ -186,6 +186,14 @@
ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f),
ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f),
fpIconAnim);
+ mAnimatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (onEndAnimation != null) {
+ onEndAnimation.run();
+ }
+ }
+ });
mAnimatorSet.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index a0ac2dc..2f9f6bc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -129,6 +129,7 @@
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.setAlternateAuthInterceptor(null);
mTransitioningFromHome = false;
+ mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
if (mCancelRunnable != null) {
mCancelRunnable.run();
@@ -165,11 +166,13 @@
mShowingUdfpsBouncer = show;
updatePauseAuth();
if (mShowingUdfpsBouncer) {
- mView.animateUdfpsBouncer();
+ mView.animateUdfpsBouncer(() ->
+ mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true));
mView.announceForAccessibility(mView.getContext().getString(
R.string.accessibility_fingerprint_bouncer));
} else {
mView.animateAwayUdfpsBouncer(null);
+ mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index cba3dab..8ad5099 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -55,8 +55,9 @@
companion object {
private const val TAG = "ControlsProviderSelectorActivity"
+ const val BACK_SHOULD_EXIT = "back_should_exit"
}
-
+ private var backShouldExit = false
private lateinit var recyclerView: RecyclerView
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
private val startingUser = listingController.currentUserId
@@ -102,13 +103,17 @@
}
}
requireViewById<View>(R.id.done).visibility = View.GONE
+
+ backShouldExit = intent.getBooleanExtra(BACK_SHOULD_EXIT, false)
}
override fun onBackPressed() {
- val i = Intent().apply {
- component = ComponentName(applicationContext, ControlsActivity::class.java)
+ if (!backShouldExit) {
+ val i = Intent().apply {
+ component = ComponentName(applicationContext, ControlsActivity::class.java)
+ }
+ startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
}
- startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
animateExitAndFinish()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 43607dd..b15bb45 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -46,6 +46,7 @@
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
+import androidx.annotation.ColorInt
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
@@ -313,7 +314,8 @@
@ColorRes bgColor: Int
) {
val bg = context.resources.getColor(R.color.control_default_background, context.theme)
- var (newClipColor, newAlpha) = if (enabled) {
+
+ val (newClipColor, newAlpha) = if (enabled) {
// allow color overrides for the enabled state only
val color = cws.control?.getCustomColor()?.let {
val state = intArrayOf(android.R.attr.state_enabled)
@@ -326,58 +328,87 @@
ALPHA_DISABLED
)
}
+ val newBaseColor = if (behavior is ToggleRangeBehavior) {
+ ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity)
+ } else {
+ bg
+ }
- clipLayer.getDrawable().apply {
+ clipLayer.drawable?.apply {
clipLayer.alpha = ALPHA_DISABLED
-
- val newBaseColor = if (behavior is ToggleRangeBehavior) {
- ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity)
- } else {
- bg
- }
stateAnimator?.cancel()
if (animated) {
- val oldColor = if (this is GradientDrawable) {
- this.color?.defaultColor ?: newClipColor
- } else {
- newClipColor
- }
- val oldBaseColor = baseLayer.color?.defaultColor ?: newBaseColor
- val oldAlpha = layout.alpha
-
- // Animate both alpha and background colors. Only animate colors for
- // GradientDrawables and not static images as used for the ThumbnailTemplate.
- stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply {
- addUpdateListener {
- alpha = it.animatedValue as Int
- if (this is GradientDrawable) {
- this.setColor(ColorUtils.blendARGB(oldColor, newClipColor,
- it.animatedFraction))
- }
- baseLayer.setColor(ColorUtils.blendARGB(oldBaseColor, newBaseColor,
- it.animatedFraction))
- layout.alpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction)
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- stateAnimator = null
- }
- })
- duration = STATE_ANIMATION_DURATION
- interpolator = Interpolators.CONTROL_STATE
- start()
- }
+ startBackgroundAnimation(this, newAlpha, newClipColor, newBaseColor)
} else {
- alpha = newAlpha
- if (this is GradientDrawable) {
- this.setColor(newClipColor)
- }
- baseLayer.setColor(newBaseColor)
- layout.alpha = 1f
+ applyBackgroundChange(
+ this, newAlpha, newClipColor, newBaseColor, newLayoutAlpha = 1f
+ )
}
}
}
+ private fun startBackgroundAnimation(
+ clipDrawable: Drawable,
+ newAlpha: Int,
+ @ColorInt newClipColor: Int,
+ @ColorInt newBaseColor: Int
+ ) {
+ val oldClipColor = if (clipDrawable is GradientDrawable) {
+ clipDrawable.color?.defaultColor ?: newClipColor
+ } else {
+ newClipColor
+ }
+ val oldBaseColor = baseLayer.color?.defaultColor ?: newBaseColor
+ val oldAlpha = layout.alpha
+
+ stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply {
+ addUpdateListener {
+ val updatedAlpha = it.animatedValue as Int
+ val updatedClipColor = ColorUtils.blendARGB(oldClipColor, newClipColor,
+ it.animatedFraction)
+ val updatedBaseColor = ColorUtils.blendARGB(oldBaseColor, newBaseColor,
+ it.animatedFraction)
+ val updatedLayoutAlpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction)
+ applyBackgroundChange(
+ clipDrawable,
+ updatedAlpha,
+ updatedClipColor,
+ updatedBaseColor,
+ updatedLayoutAlpha
+ )
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ stateAnimator = null
+ }
+ })
+ duration = STATE_ANIMATION_DURATION
+ interpolator = Interpolators.CONTROL_STATE
+ start()
+ }
+ }
+
+ /**
+ * Applies a change in background.
+ *
+ * Updates both alpha and background colors. Only updates colors for GradientDrawables and not
+ * static images as used for the ThumbnailTemplate.
+ */
+ private fun applyBackgroundChange(
+ clipDrawable: Drawable,
+ newAlpha: Int,
+ @ColorInt newClipColor: Int,
+ @ColorInt newBaseColor: Int,
+ newLayoutAlpha: Float
+ ) {
+ clipDrawable.alpha = newAlpha
+ if (clipDrawable is GradientDrawable) {
+ clipDrawable.setColor(newClipColor)
+ }
+ baseLayer.setColor(newBaseColor)
+ layout.alpha = newLayoutAlpha
+ }
+
private fun animateStatusChange(animated: Boolean, statusRowUpdater: () -> Unit) {
statusAnimator?.cancel()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 26be987..c322f45 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -217,22 +217,8 @@
}
private fun showInitialSetupView(items: List<SelectionItem>) {
- val inflater = LayoutInflater.from(context)
- inflater.inflate(R.layout.controls_no_favorites, parent, true)
-
- val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
- viewGroup.setOnClickListener { _: View -> startProviderSelectorActivity() }
-
- val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
- subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle))
-
- val iconRowGroup = parent.requireViewById(R.id.controls_icon_row) as ViewGroup
- items.forEach {
- val imageView = inflater.inflate(R.layout.controls_icon, viewGroup, false) as ImageView
- imageView.setContentDescription(it.getTitle())
- imageView.setImageDrawable(it.icon)
- iconRowGroup.addView(imageView)
- }
+ startProviderSelectorActivity()
+ onDismiss.run()
}
private fun startFavoritingActivity(si: StructureInfo) {
@@ -261,7 +247,9 @@
}
private fun startProviderSelectorActivity() {
- startActivity(Intent(activityContext, ControlsProviderSelectorActivity::class.java))
+ val i = Intent(activityContext, ControlsProviderSelectorActivity::class.java)
+ i.putExtra(ControlsProviderSelectorActivity.BACK_SHOULD_EXIT, true)
+ startActivity(i)
}
private fun startActivity(intent: Intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index b668e88..241c2a9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -64,6 +64,12 @@
mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN)
}
+ /**
+ * Is the media player visible?
+ */
+ var visible = false
+ private set
+
var visibilityChangedListener: ((Boolean) -> Unit)? = null
/**
@@ -106,11 +112,11 @@
val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD ||
statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
// mediaHost.visible required for proper animations handling
- val shouldBeVisible = mediaHost.visible &&
+ visible = mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
notifLockscreenUserManager.shouldShowLockscreenNotifications()
- if (shouldBeVisible) {
+ if (visible) {
showMediaPlayer()
} else {
hideMediaPlayer()
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index ef53233..25e6e94 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -3,6 +3,7 @@
import android.app.smartspace.SmartspaceTarget
import android.content.Context
import android.content.Intent
+import android.content.res.ColorStateList
import android.content.res.Configuration
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
@@ -380,6 +381,7 @@
private fun recreatePlayers() {
bgColor = getBackgroundColor()
+ pageIndicator.tintList = ColorStateList.valueOf(getForegroundColor())
MediaPlayerData.mediaData().forEach { (key, data) ->
removePlayer(key, dismissMediaData = false)
@@ -391,6 +393,10 @@
return context.getColor(android.R.color.system_accent2_50)
}
+ private fun getForegroundColor(): Int {
+ return context.getColor(android.R.color.system_accent2_900)
+ }
+
private fun updatePageIndicator() {
val numPages = mediaContent.getChildCount()
pageIndicator.setNumPages(numPages)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index c608dc7..e213dfe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -45,6 +45,7 @@
import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.settingslib.Utils;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -303,11 +304,23 @@
}
// App icon
- ImageView appIcon = mPlayerViewHolder.getAppIcon();
- if (data.getAppIcon() != null) {
- appIcon.setImageIcon(data.getAppIcon());
+ ImageView appIconView = mPlayerViewHolder.getAppIcon();
+ appIconView.clearColorFilter();
+ if (data.getAppIcon() != null && !data.getResumption()) {
+ appIconView.setImageIcon(data.getAppIcon());
+ int color = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.colorAccentTertiary);
+ appIconView.setColorFilter(color);
} else {
- appIcon.setImageResource(R.drawable.ic_music_note);
+ appIconView.setColorFilter(getGrayscaleFilter());
+ try {
+ Drawable icon = mContext.getPackageManager().getApplicationIcon(
+ data.getPackageName());
+ appIconView.setImageDrawable(icon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+ appIconView.setImageResource(R.drawable.ic_music_note);
+ }
}
// Song name
@@ -400,7 +413,7 @@
setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /* visible */);
}
- // If no expanded buttons, set the first view as INVISIBLE so z remains constant
+ // If no actions, set the first view as INVISIBLE so expanded height remains constant
if (actionIcons.size() == 0) {
expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.INVISIBLE);
}
@@ -514,9 +527,9 @@
// Get the logo from app's package name when applicable.
String packageName = extras.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME);
try {
- Drawable drawable = mContext.getPackageManager().getApplicationIcon(
+ icon = mContext.getPackageManager().getApplicationIcon(
packageName);
- icon = convertToGrayscale(drawable);
+ icon.setColorFilter(getGrayscaleFilter());
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "No media source icon can be fetched via package name", e);
}
@@ -646,13 +659,10 @@
return (state.getState() == PlaybackState.STATE_PLAYING);
}
- /** Convert the pass-in source drawable to a grayscale one. */
- private Drawable convertToGrayscale(Drawable drawable) {
+ private ColorMatrixColorFilter getGrayscaleFilter() {
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
- ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
- drawable.setColorFilter(filter);
- return drawable;
+ return new ColorMatrixColorFilter(matrix);
}
private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 60e832a..73dfe5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -26,6 +26,7 @@
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
+import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -35,6 +36,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import javax.inject.Inject
@@ -74,6 +76,7 @@
private val bypassController: KeyguardBypassController,
private val mediaCarouselController: MediaCarouselController,
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
+ configurationController: ConfigurationController,
wakefulnessLifecycle: WakefulnessLifecycle,
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager
) {
@@ -183,6 +186,58 @@
}
/**
+ * distance that the full shade transition takes in order for media to fully transition to the
+ * shade
+ */
+ private var distanceForFullShadeTransition = 0
+
+ /**
+ * Delay after which the media will start transitioning to the full shade on the lockscreen.
+ */
+ private var fullShadeTransitionDelay = 0
+
+ /**
+ * The amount of progress we are currently in if we're transitioning to the full shade.
+ * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
+ * shade.
+ */
+ private var fullShadeTransitionProgress = 0f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ if (bypassController.bypassEnabled) {
+ return
+ }
+ updateDesiredLocation()
+ if (value >= 0) {
+ updateTargetState()
+ applyTargetStateIfNotAnimating()
+ }
+ }
+
+ private val isTransitioningToFullShade: Boolean
+ get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled
+
+ /**
+ * Set the amount of pixels we have currently dragged down if we're transitioning to the full
+ * shade. 0.0f means we're not transitioning yet.
+ */
+ fun setTransitionToFullShadeAmount(value: Float) {
+ // If we're transitioning starting on the shade_locked, we don't want any delay and rather
+ // have it aligned with the rest of the animation
+ val delay = if (statusbarState == StatusBarState.KEYGUARD) {
+ fullShadeTransitionDelay
+ } else {
+ 0
+ }
+ val progress = MathUtils.saturate((value - delay) /
+ (distanceForFullShadeTransition - delay))
+ fullShadeTransitionProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(progress)
+ }
+
+ /**
* Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,
* we wouldn't want to transition in that case.
*/
@@ -242,6 +297,12 @@
}
init {
+ updateConfiguration()
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onDensityOrFontScaleChanged() {
+ updateConfiguration()
+ }
+ })
statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
override fun onStatePreChange(oldState: Int, newState: Int) {
// We're updating the location before the state change happens, since we want the
@@ -312,6 +373,13 @@
})
}
+ private fun updateConfiguration() {
+ distanceForFullShadeTransition = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_transition_distance)
+ fullShadeTransitionDelay = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_media_transition_start_delay)
+ }
+
/**
* Register a media host and create a view can be attached to a view hierarchy
* and where the players will be placed in when the host is the currently desired state.
@@ -546,6 +614,9 @@
if (progress >= 0) {
return progress
}
+ if (isTransitioningToFullShade) {
+ return fullShadeTransitionProgress
+ }
return -1.0f
}
@@ -643,6 +714,7 @@
val location = when {
qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
+ onLockscreen && isTransitioningToFullShade -> LOCATION_QQS
onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index c6373f5..bcef43c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -24,6 +24,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -41,6 +42,7 @@
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -116,6 +118,7 @@
final View mDivider;
final View mBottomDivider;
final CheckBox mCheckBox;
+ private String mDeviceId;
MediaDeviceBaseViewHolder(View view) {
super(view);
@@ -134,8 +137,17 @@
}
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
- mTitleIcon.setImageIcon(mController.getDeviceIconCompat(device).toIcon(mContext));
- setMargin(topMargin, bottomMargin);
+ mDeviceId = device.getId();
+ ThreadUtils.postOnBackgroundThread(() -> {
+ Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
+ ThreadUtils.postOnMainThread(() -> {
+ if (!TextUtils.equals(mDeviceId, device.getId())) {
+ return;
+ }
+ mTitleIcon.setImageIcon(icon);
+ setMargin(topMargin, bottomMargin);
+ });
+ });
}
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4e41d75..04f5199 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -364,6 +364,11 @@
}
@Override
+ public void onHomeRotationEnabled(boolean enabled) {
+ mNavigationBarView.getRotationButtonController().setHomeRotationEnabled(enabled);
+ }
+
+ @Override
public void onOverviewShown(boolean fromHome) {
// If the overview has fixed orientation that may change display to natural rotation,
// we don't want the user rotation to be reset. So after user returns to application,
@@ -951,6 +956,7 @@
if (running) {
mNavbarOverlayController.setButtonState(/* visible */false, /* force */true);
}
+ mNavigationBarView.getRotationButtonController().setRecentsAnimationRunning(running);
}
/** Restores the appearance and the transient saved state to {@link NavigationBar}. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index ddf089b..649ac87 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -71,6 +71,8 @@
private final ViewRippler mViewRippler = new ViewRippler();
private RotationButton mRotationButton;
+ private boolean mIsRecentsAnimationRunning;
+ private boolean mHomeRotationEnabled;
private int mLastRotationSuggestion;
private boolean mPendingRotationSuggestion;
private boolean mHoveringRotationSuggestion;
@@ -92,7 +94,6 @@
() -> mPendingRotationSuggestion = false;
private Animator mRotateHideAnimator;
-
private final Stub mRotationWatcher = new Stub() {
@Override
public void onRotationChanged(final int rotation) throws RemoteException {
@@ -105,7 +106,7 @@
if (shouldOverrideUserLockPrefs(rotation)) {
setRotationLockedAtAngle(rotation);
}
- setRotateSuggestionButtonState(false /* visible */, true /* forced */);
+ setRotateSuggestionButtonState(false /* visible */, true /* hideImmediately */);
}
if (mRotWatcherListener != null) {
@@ -192,10 +193,14 @@
}
void setRotateSuggestionButtonState(boolean visible) {
- setRotateSuggestionButtonState(visible, false /* force */);
+ setRotateSuggestionButtonState(visible, false /* hideImmediately */);
}
- void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
+ /**
+ * Change the visibility of rotate suggestion button. If {@code hideImmediately} is true,
+ * it doesn't wait until the completion of the running animation.
+ */
+ void setRotateSuggestionButtonState(final boolean visible, final boolean hideImmediately) {
// At any point the the button can become invisible because an a11y service became active.
// Similarly, a call to make the button visible may be rejected because an a11y service is
// active. Must account for this.
@@ -236,7 +241,7 @@
} else { // Hide
mViewRippler.stop(); // Prevent any pending ripples, force hide or not
- if (force) {
+ if (hideImmediately) {
// If a hide animator is running stop it and make invisible
if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
mRotateHideAnimator.pause();
@@ -263,12 +268,29 @@
}
}
+ void setRecentsAnimationRunning(boolean running) {
+ mIsRecentsAnimationRunning = running;
+ updateRotationButtonStateInOverview();
+ }
+
+ void setHomeRotationEnabled(boolean enabled) {
+ mHomeRotationEnabled = enabled;
+ updateRotationButtonStateInOverview();
+ }
+
+ private void updateRotationButtonStateInOverview() {
+ if (mIsRecentsAnimationRunning && !mHomeRotationEnabled) {
+ setRotateSuggestionButtonState(false, true /* hideImmediately */ );
+ }
+ }
+
void setDarkIntensity(float darkIntensity) {
mRotationButton.setDarkIntensity(darkIntensity);
}
void onRotationProposal(int rotation, int windowRotation, boolean isValid) {
- if (!mRotationButton.acceptRotationProposal()) {
+ if (!mRotationButton.acceptRotationProposal() || (!mHomeRotationEnabled
+ && mIsRecentsAnimationRunning)) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 0335319..2d0d87d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -37,6 +37,7 @@
import android.widget.Switch;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
@@ -57,7 +58,8 @@
private ViewGroup mDetailContent;
protected TextView mDetailSettingsButton;
protected TextView mDetailDoneButton;
- private QSDetailClipper mClipper;
+ @VisibleForTesting
+ QSDetailClipper mClipper;
private DetailAdapter mDetailAdapter;
private QSPanelController mQsPanelController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 53b4d5f..34c654c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -112,6 +112,17 @@
* otherwise.
*/
private boolean mTranslateWhileExpanding;
+ private boolean mPulseExpanding;
+
+ /**
+ * Are we currently transitioning from lockscreen to the full shade?
+ */
+ private boolean mTransitioningToFullShade;
+
+ /**
+ * Whether the next Quick settings
+ */
+ private boolean mAnimateNextQsUpdate;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -265,6 +276,11 @@
}
}
+ @Override
+ public boolean isFullyCollapsed() {
+ return mLastQSExpansion == 0.0f || mLastQSExpansion == -1;
+ }
+
private void setEditLocation(View view) {
View edit = view.findViewById(android.R.id.edit);
int[] loc = edit.getLocationOnScreen();
@@ -335,14 +351,22 @@
}
@Override
- public void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {
- if (showCollapsedOnKeyguard != mShowCollapsedOnKeyguard) {
- mShowCollapsedOnKeyguard = showCollapsedOnKeyguard;
+ public void setPulseExpanding(boolean pulseExpanding) {
+ if (pulseExpanding != mPulseExpanding) {
+ mPulseExpanding = pulseExpanding;
+ updateShowCollapsedOnKeyguard();
+ }
+ }
+
+ private void updateShowCollapsedOnKeyguard() {
+ boolean showCollapsed = mPulseExpanding || mTransitioningToFullShade;
+ if (showCollapsed != mShowCollapsedOnKeyguard) {
+ mShowCollapsedOnKeyguard = showCollapsed;
updateQsState();
if (mQSAnimator != null) {
- mQSAnimator.setShowCollapsedOnKeyguard(showCollapsedOnKeyguard);
+ mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
- if (!showCollapsedOnKeyguard && isKeyguardShowing()) {
+ if (!showCollapsed && isKeyguardShowing()) {
setQsExpansion(mLastQSExpansion, 0);
}
}
@@ -411,13 +435,24 @@
}
@Override
- public void setQsExpansion(float expansion, float headerTranslation) {
- if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ public void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {
+ boolean isTransitioningToFullShade = pxAmount > 0;
+ if (isTransitioningToFullShade != mTransitioningToFullShade) {
+ mTransitioningToFullShade = isTransitioningToFullShade;
+ updateShowCollapsedOnKeyguard();
+ setQsExpansion(mLastQSExpansion, mLastHeaderTranslation);
+ }
+ }
+ @Override
+ public void setQsExpansion(float expansion, float proposedTranslation) {
+ if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + proposedTranslation);
+ float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
if (mQSAnimator != null) {
final boolean showQSOnLockscreen = expansion > 0;
final boolean showQSUnlocked = headerTranslation == 0 || !mTranslateWhileExpanding;
- mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked);
+ mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked
+ || mTransitioningToFullShade);
}
mContainer.setExpansion(expansion);
final float translationScaleY = (mTranslateWhileExpanding
@@ -542,18 +577,6 @@
}
@Override
- public void animateHeaderSlidingIn(long delay) {
- if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
- // If the QS is already expanded we don't need to slide in the header as it's already
- // visible.
- if (!mQsExpanded && getView().getTranslationY() != 0) {
- mHeaderAnimating = true;
- mDelay = delay;
- getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
- }
- }
-
- @Override
public void animateHeaderSlidingOut() {
if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
if (getView().getY() == -mHeader.getHeight()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 7bde64b..8df8c63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -125,25 +125,14 @@
} else {
state.slash.isSlashed = true;
}
- state.label = mContext.getString(R.string.quick_settings_work_mode_label);
+ state.label = getTileLabel();
state.contentDescription = state.label;
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.secondaryLabel = state.value ? "" :
- mContext.getString(R.string.quick_settings_work_mode_paused);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.QS_WORKMODE;
}
-
- @Override
- protected String composeChangeAnnouncement() {
- if (mState.value) {
- return mContext.getString(R.string.accessibility_quick_settings_work_mode_changed_on);
- } else {
- return mContext.getString(R.string.accessibility_quick_settings_work_mode_changed_off);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 63adbd0..20c3e81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -259,6 +259,21 @@
}
}
+ @Override
+ public void setHomeRotationEnabled(boolean enabled) {
+ if (!verifyCaller("setHomeRotationEnabled")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mHandler.post(() -> {
+ mHandler.post(() -> notifyHomeRotationEnabled(enabled));
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private boolean sendEvent(int action, int code) {
long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
@@ -847,6 +862,12 @@
}
}
+ private void notifyHomeRotationEnabled(boolean enabled) {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
+ }
+ }
+
private void notifyConnectionChanged() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
@@ -994,6 +1015,7 @@
default void onToggleRecentApps() {}
/** Notify changes in the nav bar button alpha */
default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
+ default void onHomeRotationEnabled(boolean enabled) {}
default void onSystemUiStateChanged(int sysuiStateFlags) {}
default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
default void onAssistantGestureCompletion(float velocity) {}
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 1a5c9ee..7530681 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -294,7 +294,6 @@
/**
* Make bottom edge concave so overlap between layers is not visible for alphas between 0 and 1
- * @return height of concavity
*/
public void enableBottomEdgeConcave(boolean clipScrim) {
if (mDrawable instanceof ScrimDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
deleted file mode 100644
index 0378123..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-import com.android.systemui.ExpandHelper;
-import com.android.systemui.Gefingerpoken;
-import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.notification.row.ExpandableView;
-
-/**
- * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
- * the notification where the drag started.
- */
-public class DragDownHelper implements Gefingerpoken {
-
- private static final float RUBBERBAND_FACTOR_EXPANDABLE = 0.5f;
- private static final float RUBBERBAND_FACTOR_STATIC = 0.15f;
-
- private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
-
- private int mMinDragDistance;
- private final FalsingManager mFalsingManager;
- private ExpandHelper.Callback mCallback;
- private float mInitialTouchX;
- private float mInitialTouchY;
- private boolean mDraggingDown;
- private final float mTouchSlop;
- private final float mSlopMultiplier;
- private DragDownCallback mDragDownCallback;
- private View mHost;
- private final int[] mTemp2 = new int[2];
- private boolean mDraggedFarEnough;
- private ExpandableView mStartingChild;
- private float mLastHeight;
- private FalsingCollector mFalsingCollector;
-
- public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
- DragDownCallback dragDownCallback, FalsingManager falsingManager,
- FalsingCollector falsingCollector) {
- mMinDragDistance = context.getResources().getDimensionPixelSize(
- R.dimen.keyguard_drag_down_min_distance);
- mFalsingManager = falsingManager;
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mTouchSlop = configuration.getScaledTouchSlop();
- mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
- mCallback = callback;
- mDragDownCallback = dragDownCallback;
- mHost = host;
- mFalsingCollector = falsingCollector;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- final float x = event.getX();
- final float y = event.getY();
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mDraggedFarEnough = false;
- mDraggingDown = false;
- mStartingChild = null;
- mInitialTouchY = y;
- mInitialTouchX = x;
- break;
-
- case MotionEvent.ACTION_MOVE:
- final float h = y - mInitialTouchY;
- // Adjust the touch slop if another gesture may be being performed.
- final float touchSlop =
- event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
- ? mTouchSlop * mSlopMultiplier
- : mTouchSlop;
- if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
- mFalsingCollector.onNotificationStartDraggingDown();
- mDraggingDown = true;
- captureStartingChild(mInitialTouchX, mInitialTouchY);
- mInitialTouchY = y;
- mInitialTouchX = x;
- mDragDownCallback.onTouchSlopExceeded();
- return mStartingChild != null || mDragDownCallback.isDragDownAnywhereEnabled();
- }
- break;
- }
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mDraggingDown) {
- return false;
- }
- final float x = event.getX();
- final float y = event.getY();
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_MOVE:
- mLastHeight = y - mInitialTouchY;
- captureStartingChild(mInitialTouchX, mInitialTouchY);
- if (mStartingChild != null) {
- handleExpansion(mLastHeight, mStartingChild);
- } else {
- mDragDownCallback.setEmptyDragAmount(mLastHeight);
- }
- if (mLastHeight > mMinDragDistance) {
- if (!mDraggedFarEnough) {
- mDraggedFarEnough = true;
- mDragDownCallback.onCrossedThreshold(true);
- }
- } else {
- if (mDraggedFarEnough) {
- mDraggedFarEnough = false;
- mDragDownCallback.onCrossedThreshold(false);
- }
- }
- return true;
- case MotionEvent.ACTION_UP:
- if (!mFalsingManager.isUnlockingDisabled() && mDragDownCallback.canDragDown()
- && !isFalseTouch()) {
- mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY));
- if (mStartingChild == null) {
- cancelExpansion();
- } else {
- mCallback.setUserLockedChild(mStartingChild, false);
- mStartingChild = null;
- }
- mDraggingDown = false;
- } else {
- stopDragging();
- return false;
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- stopDragging();
- return false;
- }
- return false;
- }
-
- private boolean isFalseTouch() {
- if (!mDragDownCallback.isFalsingCheckNeeded()) {
- return false;
- }
- return mFalsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN) || !mDraggedFarEnough;
- }
-
- private void captureStartingChild(float x, float y) {
- if (mStartingChild == null) {
- mStartingChild = findView(x, y);
- if (mStartingChild != null) {
- if (mDragDownCallback.isDragDownEnabledForView(mStartingChild)) {
- mCallback.setUserLockedChild(mStartingChild, true);
- } else {
- mStartingChild = null;
- }
- }
- }
- }
-
- private void handleExpansion(float heightDelta, ExpandableView child) {
- if (heightDelta < 0) {
- heightDelta = 0;
- }
- boolean expandable = child.isContentExpandable();
- float rubberbandFactor = expandable
- ? RUBBERBAND_FACTOR_EXPANDABLE
- : RUBBERBAND_FACTOR_STATIC;
- float rubberband = heightDelta * rubberbandFactor;
- if (expandable
- && (rubberband + child.getCollapsedHeight()) > child.getMaxContentHeight()) {
- float overshoot =
- (rubberband + child.getCollapsedHeight()) - child.getMaxContentHeight();
- overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
- rubberband -= overshoot;
- }
- child.setActualHeight((int) (child.getCollapsedHeight() + rubberband));
- }
-
- private void cancelExpansion(final ExpandableView child) {
- if (child.getActualHeight() == child.getCollapsedHeight()) {
- mCallback.setUserLockedChild(child, false);
- return;
- }
- ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
- child.getActualHeight(), child.getCollapsedHeight());
- anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCallback.setUserLockedChild(child, false);
- }
- });
- anim.start();
- }
-
- private void cancelExpansion() {
- ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0);
- anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
- anim.addUpdateListener(animation -> {
- mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue());
- });
- anim.start();
- }
-
- private void stopDragging() {
- mFalsingCollector.onNotificationStopDraggingDown();
- if (mStartingChild != null) {
- cancelExpansion(mStartingChild);
- mStartingChild = null;
- } else {
- cancelExpansion();
- }
- mDraggingDown = false;
- mDragDownCallback.onDragDownReset();
- }
-
- private ExpandableView findView(float x, float y) {
- mHost.getLocationOnScreen(mTemp2);
- x += mTemp2[0];
- y += mTemp2[1];
- return mCallback.getChildAtRawPosition(x, y);
- }
-
- public boolean isDraggingDown() {
- return mDraggingDown;
- }
-
- public boolean isDragDownEnabled() {
- return mDragDownCallback.isDragDownEnabledForView(null);
- }
-
- public interface DragDownCallback {
-
- /**
- * @return true if the interaction is accepted, false if it should be cancelled
- */
- boolean canDragDown();
-
- /** Call when a view has been dragged. */
- void onDraggedDown(View startingChild, int dragLengthY);
- void onDragDownReset();
-
- /**
- * The user has dragged either above or below the threshold
- * @param above whether he dragged above it
- */
- void onCrossedThreshold(boolean above);
- void onTouchSlopExceeded();
- void setEmptyDragAmount(float amount);
- boolean isFalsingCheckNeeded();
-
- /**
- * Is dragging down enabled on a given view
- * @param view The view to check or {@code null} to check if it's enabled at all
- */
- boolean isDragDownEnabledForView(ExpandableView view);
-
- /**
- * @return if drag down is enabled anywhere, not just on selected views.
- */
- boolean isDragDownAnywhereEnabled();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
new file mode 100644
index 0000000..12f569c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -0,0 +1,667 @@
+package com.android.systemui.statusbar
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.Configuration
+import android.os.SystemClock
+import android.util.DisplayMetrics
+import android.util.MathUtils
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewConfiguration
+import androidx.annotation.VisibleForTesting
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent
+import com.android.systemui.ExpandHelper
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.MediaHierarchyManager
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent
+import com.android.systemui.statusbar.phone.NotificationPanelViewController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.StatusBar
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.Utils
+import javax.inject.Inject
+
+private const val SPRING_BACK_ANIMATION_LENGTH_MS = 375L
+private const val RUBBERBAND_FACTOR_STATIC = 0.15f
+private const val RUBBERBAND_FACTOR_EXPANDABLE = 0.5f
+
+/**
+ * A class that controls the lockscreen to shade transition
+ */
+@SysUISingleton
+class LockscreenShadeTransitionController @Inject constructor(
+ private val statusBarStateController: SysuiStatusBarStateController,
+ private val lockscreenGestureLogger: LockscreenGestureLogger,
+ private val keyguardBypassController: KeyguardBypassController,
+ private val lockScreenUserManager: NotificationLockscreenUserManager,
+ private val falsingCollector: FalsingCollector,
+ private val ambientState: AmbientState,
+ private val displayMetrics: DisplayMetrics,
+ private val mediaHierarchyManager: MediaHierarchyManager,
+ private val scrimController: ScrimController,
+ private val featureFlags: FeatureFlags,
+ private val context: Context,
+ configurationController: ConfigurationController,
+ falsingManager: FalsingManager
+) {
+ private var useSplitShade: Boolean = false
+ private lateinit var nsslController: NotificationStackScrollLayoutController
+ lateinit var notificationPanelController: NotificationPanelViewController
+ lateinit var statusbar: StatusBar
+ lateinit var qS: QS
+
+ /**
+ * A handler that handles the next keyguard dismiss animation.
+ */
+ private var animationHandlerOnKeyguardDismiss: ((Long) -> Unit)? = null
+
+ /**
+ * The entry that was just dragged down on.
+ */
+ private var draggedDownEntry: NotificationEntry? = null
+
+ /**
+ * The current animator if any
+ */
+ @VisibleForTesting
+ internal var dragDownAnimator: ValueAnimator? = null
+
+ /**
+ * Distance that the full shade transition takes in order for scrim to fully transition to
+ * the shade (in alpha)
+ */
+ private var scrimTransitionDistance = 0
+
+ /**
+ * Distance that the full transition takes in order for us to fully transition to the shade
+ */
+ private var fullTransitionDistance = 0
+
+ /**
+ * Flag to make sure that the dragDownAmount is applied to the listeners even when in the
+ * locked down shade.
+ */
+ private var forceApplyAmount = false
+
+ /**
+ * A flag to suppress the default animation when unlocking in the locked down shade.
+ */
+ private var nextHideKeyguardNeedsNoAnimation = false
+
+ /**
+ * The touch helper responsible for the drag down animation.
+ */
+ val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context)
+
+ init {
+ updateResources()
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateResources()
+ touchHelper.updateResources(context)
+ }
+ })
+ }
+
+ private fun updateResources() {
+ scrimTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_scrim_transition_distance)
+ fullTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_transition_distance)
+ useSplitShade = Utils.shouldUseSplitNotificationShade(featureFlags, context.resources)
+ }
+
+ fun setStackScroller(nsslController: NotificationStackScrollLayoutController) {
+ this.nsslController = nsslController
+ touchHelper.host = nsslController.view
+ touchHelper.expandCallback = nsslController.expandHelperCallback
+ }
+
+ /**
+ * Initialize the shelf controller such that clicks on it will expand the shade
+ */
+ fun bindController(notificationShelfController: NotificationShelfController) {
+ // Bind the click listener of the shelf to go to the full shade
+ notificationShelfController.setOnClickListener {
+ if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+ statusbar.wakeUpIfDozing(SystemClock.uptimeMillis(), it, "SHADE_CLICK")
+ goToLockedShade(it)
+ }
+ }
+ }
+
+ /**
+ * @return true if the interaction is accepted, false if it should be cancelled
+ */
+ internal fun canDragDown(): Boolean {
+ return (statusBarStateController.state == StatusBarState.KEYGUARD ||
+ nsslController.isInLockedDownShade()) &&
+ qS.isFullyCollapsed
+ }
+
+ /**
+ * Called by the touch helper when when a gesture has completed all the way and released.
+ */
+ internal fun onDraggedDown(startingChild: View?, dragLengthY: Int) {
+ if (canDragDown()) {
+ if (nsslController.isInLockedDownShade()) {
+ statusBarStateController.setLeaveOpenOnKeyguardHide(true)
+ statusbar.dismissKeyguardThenExecute(OnDismissAction {
+ nextHideKeyguardNeedsNoAnimation = true
+ false
+ },
+ null /* cancelRunnable */, false /* afterKeyguardGone */)
+ } else {
+ lockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_SHADE,
+ (dragLengthY / displayMetrics.density).toInt(),
+ 0 /* velocityDp */)
+ lockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN)
+ if (!ambientState.isDozing() || startingChild != null) {
+ // go to locked shade while animating the drag down amount from its current
+ // value
+ val animationHandler = { delay: Long ->
+ if (startingChild is ExpandableNotificationRow) {
+ startingChild.onExpandedByGesture(
+ true /* drag down is always an open */)
+ }
+ notificationPanelController.animateToFullShade(delay)
+ notificationPanelController.setTransitionToFullShadeAmount(0f,
+ true /* animated */, delay)
+
+ // Let's reset ourselves, ready for the next animation
+
+ // changing to shade locked will make isInLockDownShade true, so let's
+ // override that
+ forceApplyAmount = true
+ // Reset the behavior. At this point the animation is already started
+ dragDownAmount = 0f
+ forceApplyAmount = false
+ }
+ val cancelRunnable = Runnable { setDragDownAmountAnimated(0f) }
+ goToLockedShadeInternal(startingChild, animationHandler, cancelRunnable)
+ }
+ }
+ } else {
+ setDragDownAmountAnimated(0f)
+ }
+ }
+
+ /**
+ * Called by the touch helper when the drag down was aborted and should be reset.
+ */
+ internal fun onDragDownReset() {
+ nsslController.setDimmed(true /* dimmed */, true /* animated */)
+ nsslController.resetScrollPosition()
+ nsslController.resetCheckSnoozeLeavebehind()
+ setDragDownAmountAnimated(0f)
+ }
+
+ /**
+ * The user has dragged either above or below the threshold which changes the dimmed state.
+ * @param above whether they dragged above it
+ */
+ internal fun onCrossedThreshold(above: Boolean) {
+ nsslController.setDimmed(!above /* dimmed */, true /* animate */)
+ }
+
+ /**
+ * Called by the touch helper when the drag down was started
+ */
+ internal fun onDragDownStarted() {
+ nsslController.cancelLongPress()
+ nsslController.checkSnoozeLeavebehind()
+ dragDownAnimator?.cancel()
+ }
+
+ /**
+ * Do we need a falsing check currently?
+ */
+ internal val isFalsingCheckNeeded: Boolean
+ get() = statusBarStateController.state == StatusBarState.KEYGUARD
+
+ /**
+ * Is dragging down enabled on a given view
+ * @param view The view to check or `null` to check if it's enabled at all
+ */
+ internal fun isDragDownEnabledForView(view: ExpandableView?): Boolean {
+ if (isDragDownAnywhereEnabled) {
+ return true
+ }
+ if (nsslController.isInLockedDownShade()) {
+ if (view == null) {
+ // Dragging down is allowed in general
+ return true
+ }
+ if (view is ExpandableNotificationRow) {
+ // Only drag down on sensitive views, otherwise the ExpandHelper will take this
+ return view.entry.isSensitive
+ }
+ }
+ return false
+ }
+
+ /**
+ * @return if drag down is enabled anywhere, not just on selected views.
+ */
+ internal val isDragDownAnywhereEnabled: Boolean
+ get() = (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
+ !keyguardBypassController.bypassEnabled &&
+ qS.isFullyCollapsed)
+
+ /**
+ * The amount in pixels that the user has dragged down.
+ */
+ internal var dragDownAmount = 0f
+ set(value) {
+ if (field != value || forceApplyAmount) {
+ field = value
+ if (!nsslController.isInLockedDownShade() || forceApplyAmount) {
+ nsslController.setTransitionToFullShadeAmount(field)
+ notificationPanelController.setTransitionToFullShadeAmount(field,
+ false /* animate */, 0 /* delay */)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+ val scrimProgress = MathUtils.saturate(field / scrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ // TODO: appear qs also in split shade
+ val qsAmount = if (useSplitShade) 0f else field
+ qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */)
+ }
+ }
+ }
+
+ private fun setDragDownAmountAnimated(
+ target: Float,
+ delay: Long = 0,
+ endlistener: (() -> Unit)? = null
+ ) {
+ val dragDownAnimator = ValueAnimator.ofFloat(dragDownAmount, target)
+ dragDownAnimator.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ dragDownAnimator.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+ dragDownAnimator.addUpdateListener { animation: ValueAnimator ->
+ dragDownAmount = animation.animatedValue as Float
+ }
+ if (delay > 0) {
+ dragDownAnimator.startDelay = delay
+ }
+ if (endlistener != null) {
+ dragDownAnimator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ endlistener.invoke()
+ }
+ })
+ }
+ dragDownAnimator.start()
+ this.dragDownAnimator = dragDownAnimator
+ }
+
+ /**
+ * Animate appear the drag down amount.
+ */
+ private fun animateAppear(delay: Long = 0) {
+ // changing to shade locked will make isInLockDownShade true, so let's override
+ // that
+ forceApplyAmount = true
+
+ // we set the value initially to 1 pixel, since that will make sure we're
+ // transitioning to the full shade. this is important to avoid flickering,
+ // as the below animation only starts once the shade is unlocked, which can
+ // be a couple of frames later. if we're setting it to 0, it will use the
+ // default inset and therefore flicker
+ dragDownAmount = 1f
+ setDragDownAmountAnimated(fullTransitionDistance.toFloat(), delay = delay) {
+ // End listener:
+ // Reset
+ dragDownAmount = 0f
+ forceApplyAmount = false
+ }
+ }
+
+ /**
+ * Ask this controller to go to the locked shade, changing the state change and doing
+ * an animation, where the qs appears from 0 from the top
+ *
+ * If secure with redaction: Show bouncer, go to unlocked shade.
+ * If secure without redaction or no security: Go to [StatusBarState.SHADE_LOCKED].
+ *
+ * @param expandView The view to expand after going to the shade
+ * @param needsQSAnimation if this needs the quick settings to slide in from the top or if
+ * that's already handled separately
+ */
+ @JvmOverloads
+ fun goToLockedShade(expandedView: View?, needsQSAnimation: Boolean = true) {
+ if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+ val animationHandler: ((Long) -> Unit)?
+ if (needsQSAnimation) {
+ // Let's use the default animation
+ animationHandler = null
+ } else {
+ // Let's only animate notifications
+ animationHandler = { delay: Long ->
+ notificationPanelController.animateToFullShade(delay)
+ }
+ }
+ goToLockedShadeInternal(expandedView, animationHandler,
+ cancelAction = null)
+ }
+ }
+
+ /**
+ * If secure with redaction: Show bouncer, go to unlocked shade.
+ *
+ * If secure without redaction or no security: Go to [StatusBarState.SHADE_LOCKED].
+ *
+ * @param expandView The view to expand after going to the shade.
+ * @param animationHandler The handler which performs the go to full shade animation. If null,
+ * the default handler will do the animation, otherwise the caller is
+ * responsible for the animation. The input value is a Long for the
+ * delay for the animation.
+ * @param cancelAction The runnable to invoke when the transition is aborted. This happens if
+ * the user goes to the bouncer and goes back.
+ */
+ private fun goToLockedShadeInternal(
+ expandView: View?,
+ animationHandler: ((Long) -> Unit)? = null,
+ cancelAction: Runnable? = null
+ ) {
+ if (statusbar.isShadeDisabled) {
+ cancelAction?.run()
+ return
+ }
+ var userId: Int = lockScreenUserManager.getCurrentUserId()
+ var entry: NotificationEntry? = null
+ if (expandView is ExpandableNotificationRow) {
+ entry = expandView.entry
+ entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */)
+ // Indicate that the group expansion is changing at this time -- this way the group
+ // and children backgrounds / divider animations will look correct.
+ entry.setGroupExpansionChanging(true)
+ userId = entry.sbn.userId
+ }
+ var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic(
+ lockScreenUserManager.getCurrentUserId()) ||
+ !lockScreenUserManager.shouldShowLockscreenNotifications() ||
+ falsingCollector.shouldEnforceBouncer())
+ if (keyguardBypassController.bypassEnabled) {
+ fullShadeNeedsBouncer = false
+ }
+ if (lockScreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
+ statusBarStateController.setLeaveOpenOnKeyguardHide(true)
+ var onDismissAction: OnDismissAction? = null
+ if (animationHandler != null) {
+ onDismissAction = OnDismissAction {
+ // We're waiting on keyguard to hide before triggering the action,
+ // as that will make the animation work properly
+ animationHandlerOnKeyguardDismiss = animationHandler
+ false
+ }
+ }
+ val cancelHandler = Runnable {
+ draggedDownEntry?.apply {
+ setUserLocked(false)
+ notifyHeightChanged(false /* needsAnimation */)
+ draggedDownEntry = null
+ }
+ cancelAction?.run()
+ }
+ statusbar.showBouncerWithDimissAndCancelIfKeyguard(onDismissAction, cancelHandler)
+ draggedDownEntry = entry
+ } else {
+ statusBarStateController.setState(StatusBarState.SHADE_LOCKED)
+ // This call needs to be after updating the shade state since otherwise
+ // the scrimstate resets too early
+ if (animationHandler != null) {
+ animationHandler.invoke(0 /* delay */)
+ } else {
+ performDefaultGoToFullShadeAnimation(0)
+ }
+ }
+ }
+
+ /**
+ * Notify this handler that the keyguard was just dismissed and that a animation to
+ * the full shade should happen.
+ */
+ fun onHideKeyguard(delay: Long) {
+ if (animationHandlerOnKeyguardDismiss != null) {
+ animationHandlerOnKeyguardDismiss!!.invoke(delay)
+ animationHandlerOnKeyguardDismiss = null
+ } else {
+ if (nextHideKeyguardNeedsNoAnimation) {
+ nextHideKeyguardNeedsNoAnimation = false
+ } else {
+ performDefaultGoToFullShadeAnimation(delay)
+ }
+ }
+ draggedDownEntry?.apply {
+ setUserLocked(false)
+ draggedDownEntry = null
+ }
+ }
+
+ /**
+ * Perform the default appear animation when going to the full shade. This is called when
+ * not triggered by gestures, e.g. when clicking on the shelf or expand button.
+ */
+ private fun performDefaultGoToFullShadeAnimation(delay: Long) {
+ notificationPanelController.animateToFullShade(delay)
+ animateAppear(delay)
+ }
+}
+
+/**
+ * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
+ * the notification where the drag started.
+ */
+class DragDownHelper(
+ private val falsingManager: FalsingManager,
+ private val falsingCollector: FalsingCollector,
+ private val dragDownCallback: LockscreenShadeTransitionController,
+ context: Context
+) : Gefingerpoken {
+
+ private var dragDownAmountOnStart = 0.0f
+ lateinit var expandCallback: ExpandHelper.Callback
+ lateinit var host: View
+
+ private var minDragDistance = 0
+ private var initialTouchX = 0f
+ private var initialTouchY = 0f
+ private var touchSlop = 0f
+ private var slopMultiplier = 0f
+ private val temp2 = IntArray(2)
+ private var draggedFarEnough = false
+ private var startingChild: ExpandableView? = null
+ private var lastHeight = 0f
+ var isDraggingDown = false
+ private set
+
+ private val isFalseTouch: Boolean
+ get() {
+ return if (!dragDownCallback.isFalsingCheckNeeded) {
+ false
+ } else {
+ falsingManager.isFalseTouch(Classifier.NOTIFICATION_DRAG_DOWN) || !draggedFarEnough
+ }
+ }
+
+ val isDragDownEnabled: Boolean
+ get() = dragDownCallback.isDragDownEnabledForView(null)
+
+ init {
+ updateResources(context)
+ }
+
+ fun updateResources(context: Context) {
+ minDragDistance = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance)
+ val configuration = ViewConfiguration.get(context)
+ touchSlop = configuration.scaledTouchSlop.toFloat()
+ slopMultiplier = configuration.scaledAmbiguousGestureMultiplier
+ }
+
+ override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
+ val x = event.x
+ val y = event.y
+ when (event.actionMasked) {
+ MotionEvent.ACTION_DOWN -> {
+ draggedFarEnough = false
+ isDraggingDown = false
+ startingChild = null
+ initialTouchY = y
+ initialTouchX = x
+ }
+ MotionEvent.ACTION_MOVE -> {
+ val h = y - initialTouchY
+ // Adjust the touch slop if another gesture may be being performed.
+ val touchSlop = if (event.classification
+ == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE)
+ touchSlop * slopMultiplier
+ else
+ touchSlop
+ if (h > touchSlop && h > Math.abs(x - initialTouchX)) {
+ falsingCollector.onNotificationStartDraggingDown()
+ isDraggingDown = true
+ captureStartingChild(initialTouchX, initialTouchY)
+ initialTouchY = y
+ initialTouchX = x
+ dragDownCallback.onDragDownStarted()
+ dragDownAmountOnStart = dragDownCallback.dragDownAmount
+ return startingChild != null || dragDownCallback.isDragDownAnywhereEnabled
+ }
+ }
+ }
+ return false
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (!isDraggingDown) {
+ return false
+ }
+ val x = event.x
+ val y = event.y
+ when (event.actionMasked) {
+ MotionEvent.ACTION_MOVE -> {
+ lastHeight = y - initialTouchY
+ captureStartingChild(initialTouchX, initialTouchY)
+ dragDownCallback.dragDownAmount = lastHeight + dragDownAmountOnStart
+ if (startingChild != null) {
+ handleExpansion(lastHeight, startingChild!!)
+ }
+ if (lastHeight > minDragDistance) {
+ if (!draggedFarEnough) {
+ draggedFarEnough = true
+ dragDownCallback.onCrossedThreshold(true)
+ }
+ } else {
+ if (draggedFarEnough) {
+ draggedFarEnough = false
+ dragDownCallback.onCrossedThreshold(false)
+ }
+ }
+ return true
+ }
+ MotionEvent.ACTION_UP -> if (!falsingManager.isUnlockingDisabled && !isFalseTouch &&
+ dragDownCallback.canDragDown()) {
+ dragDownCallback.onDraggedDown(startingChild, (y - initialTouchY).toInt())
+ if (startingChild != null) {
+ expandCallback.setUserLockedChild(startingChild, false)
+ startingChild = null
+ }
+ isDraggingDown = false
+ } else {
+ stopDragging()
+ return false
+ }
+ MotionEvent.ACTION_CANCEL -> {
+ stopDragging()
+ return false
+ }
+ }
+ return false
+ }
+
+ private fun captureStartingChild(x: Float, y: Float) {
+ if (startingChild == null) {
+ startingChild = findView(x, y)
+ if (startingChild != null) {
+ if (dragDownCallback.isDragDownEnabledForView(startingChild)) {
+ expandCallback.setUserLockedChild(startingChild, true)
+ } else {
+ startingChild = null
+ }
+ }
+ }
+ }
+
+ private fun handleExpansion(heightDelta: Float, child: ExpandableView) {
+ var hDelta = heightDelta
+ if (hDelta < 0) {
+ hDelta = 0f
+ }
+ val expandable = child.isContentExpandable
+ val rubberbandFactor = if (expandable) {
+ RUBBERBAND_FACTOR_EXPANDABLE
+ } else {
+ RUBBERBAND_FACTOR_STATIC
+ }
+ var rubberband = hDelta * rubberbandFactor
+ if (expandable && rubberband + child.collapsedHeight > child.maxContentHeight) {
+ var overshoot = rubberband + child.collapsedHeight - child.maxContentHeight
+ overshoot *= 1 - RUBBERBAND_FACTOR_STATIC
+ rubberband -= overshoot
+ }
+ child.actualHeight = (child.collapsedHeight + rubberband).toInt()
+ }
+
+ private fun cancelChildExpansion(child: ExpandableView) {
+ if (child.actualHeight == child.collapsedHeight) {
+ expandCallback.setUserLockedChild(child, false)
+ return
+ }
+ val anim = ObjectAnimator.ofInt(child, "actualHeight",
+ child.actualHeight, child.collapsedHeight)
+ anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+ anim.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ expandCallback.setUserLockedChild(child, false)
+ }
+ })
+ anim.start()
+ }
+
+ private fun stopDragging() {
+ falsingCollector.onNotificationStopDraggingDown()
+ if (startingChild != null) {
+ cancelChildExpansion(startingChild!!)
+ startingChild = null
+ }
+ isDraggingDown = false
+ dragDownCallback.onDragDownReset()
+ }
+
+ private fun findView(x: Float, y: Float): ExpandableView? {
+ host.getLocationOnScreen(temp2)
+ return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1])
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 84465a8..9765ace 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -42,7 +42,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.ShadeController
import javax.inject.Inject
import kotlin.math.max
@@ -59,6 +58,7 @@
private val roundnessManager: NotificationRoundnessManager,
private val statusBarStateController: StatusBarStateController,
private val falsingManager: FalsingManager,
+ private val lockscreenShadeTransitionController: LockscreenShadeTransitionController,
private val falsingCollector: FalsingCollector
) : Gefingerpoken {
companion object {
@@ -66,7 +66,6 @@
private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
}
private val mPowerManager: PowerManager?
- private lateinit var shadeController: ShadeController
private val mMinDragDistance: Int
private var mInitialTouchX: Float = 0.0f
@@ -95,7 +94,7 @@
var leavingLockscreen: Boolean = false
private set
private val mTouchSlop: Float
- private lateinit var expansionCallback: ExpansionCallback
+ private lateinit var overStretchHandler: OverStretchHandler
private lateinit var stackScrollerController: NotificationStackScrollLayoutController
private val mTemp2 = IntArray(2)
private var mDraggedFarEnough: Boolean = false
@@ -103,7 +102,7 @@
private var mPulsing: Boolean = false
var isWakingToShadeLocked: Boolean = false
private set
- private var mEmptyDragAmount: Float = 0.0f
+ private var overStretchAmount: Float = 0.0f
private var mWakeUpHeight: Float = 0.0f
private var mReachedWakeUpHeight: Boolean = false
private var velocityTracker: VelocityTracker? = null
@@ -215,6 +214,7 @@
private fun finishExpansion() {
resetClock()
+ val startingChild = mStartingChild
if (mStartingChild != null) {
setUserLocked(mStartingChild!!, false)
mStartingChild = null
@@ -225,7 +225,8 @@
mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
"com.android.systemui:PULSEDRAG")
}
- shadeController.goToLockedShade(mStartingChild)
+ lockscreenShadeTransitionController.goToLockedShade(startingChild,
+ needsQSAnimation = false)
leavingLockscreen = true
isExpanding = false
if (mStartingChild is ExpandableNotificationRow) {
@@ -252,8 +253,8 @@
true /* increaseSpeed */)
expansionHeight = max(mWakeUpHeight, expansionHeight)
}
- val emptyDragAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
- setEmptyDragAmount(emptyDragAmount * RUBBERBAND_FACTOR_STATIC)
+ val dragDownAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
+ setOverStretchAmount(dragDownAmount)
}
private fun captureStartingChild(x: Float, y: Float) {
@@ -265,9 +266,9 @@
}
}
- private fun setEmptyDragAmount(amount: Float) {
- mEmptyDragAmount = amount
- expansionCallback.setEmptyDragAmount(amount)
+ private fun setOverStretchAmount(amount: Float) {
+ overStretchAmount = amount
+ overStretchHandler.setOverStretchAmount(amount)
}
private fun reset(child: ExpandableView) {
@@ -294,10 +295,12 @@
}
private fun resetClock() {
- val anim = ValueAnimator.ofFloat(mEmptyDragAmount, 0f)
+ val anim = ValueAnimator.ofFloat(overStretchAmount, 0f)
anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
- anim.addUpdateListener { animation -> setEmptyDragAmount(animation.animatedValue as Float) }
+ anim.addUpdateListener {
+ animation -> setOverStretchAmount(animation.animatedValue as Float)
+ }
anim.start()
}
@@ -329,11 +332,9 @@
fun setUp(
stackScrollerController: NotificationStackScrollLayoutController,
- expansionCallback: ExpansionCallback,
- shadeController: ShadeController
+ overStrechHandler: OverStretchHandler
) {
- this.expansionCallback = expansionCallback
- this.shadeController = shadeController
+ this.overStretchHandler = overStrechHandler
this.stackScrollerController = stackScrollerController
}
@@ -345,7 +346,11 @@
isWakingToShadeLocked = false
}
- interface ExpansionCallback {
- fun setEmptyDragAmount(amount: Float)
+ interface OverStretchHandler {
+
+ /**
+ * Set the overstretch amount in pixels This will be rubberbanded later
+ */
+ fun setOverStretchAmount(amount: Float)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index a0d5eef..71546ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -106,6 +106,10 @@
return view
}
+ fun requestSmartspaceUpdate() {
+ session?.requestSmartspaceUpdate()
+ }
+
private fun buildView(parent: ViewGroup) {
if (plugin == null) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index caf4720..66d2347 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -95,6 +95,7 @@
/** Height of the notifications panel without top padding when expansion completes. */
private float mStackEndHeight;
+ private float mTransitionToFullShadeAmount;
/**
* @return Height of the notifications panel without top padding when expansion completes.
@@ -595,6 +596,21 @@
}
/**
+ * Set the amount of pixels we have currently dragged down if we're transitioning to the full
+ * shade. 0.0f means we're not transitioning yet.
+ */
+ public void setTransitionToFullShadeAmount(float transitionToFullShadeAmount) {
+ mTransitionToFullShadeAmount = transitionToFullShadeAmount;
+ }
+
+ /**
+ * get
+ */
+ public float getTransitionToFullShadeAmount() {
+ return mTransitionToFullShadeAmount;
+ }
+
+ /**
* Returns the currently tracked heads up row, if there is one and it is currently above the
* shelf (still appearing).
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 4dbdb13..a804ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -46,7 +46,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
@@ -71,17 +70,14 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardSliceView;
import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -89,7 +85,6 @@
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -108,9 +103,6 @@
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -151,7 +143,6 @@
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
- private final SysuiStatusBarStateController mStatusbarStateController;
private ExpandHelper mExpandHelper;
private NotificationSwipeHelper mSwipeHelper;
@@ -433,13 +424,9 @@
private ShadeController mShadeController;
private Runnable mOnStackYChanged;
- private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
- private final LockscreenGestureLogger mLockscreenGestureLogger =
- Dependency.get(LockscreenGestureLogger.class);
protected boolean mClearAllEnabled;
private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
- private NotificationPanelViewController mNotificationPanelController;
private final NotificationSectionsManager mSectionsManager;
private ForegroundServiceDungeonView mFgsSectionView;
@@ -449,6 +436,11 @@
private boolean mWillExpand;
private int mGapHeight;
+ /**
+ * The extra inset during the full shade transition
+ */
+ private float mExtraTopInsetForFullShadeTransition;
+
private int mWaterfallTopInset;
private NotificationStackScrollLayoutController mController;
@@ -496,7 +488,6 @@
NotificationSectionsManager notificationSectionsManager,
GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager,
- SysuiStatusBarStateController statusbarStateController,
AmbientState ambientState,
FeatureFlags featureFlags) {
super(context, attrs, 0, 0);
@@ -535,7 +526,6 @@
mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
mGroupMembershipManager = groupMembershipManager;
mGroupExpansionManager = groupExpansionManager;
- mStatusbarStateController = statusbarStateController;
}
void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) {
@@ -1142,8 +1132,9 @@
*/
private void updateStackPosition() {
// Consider interpolating from an mExpansionStartY for use on lockscreen and AOD
+ float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition;
final float fraction = mAmbientState.getExpansionFraction();
- final float stackY = MathUtils.lerp(0, mTopPadding, fraction);
+ final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
mAmbientState.setStackY(stackY);
if (mOnStackYChanged != null) {
mOnStackYChanged.run();
@@ -1151,7 +1142,7 @@
if (mQsExpansionFraction <= 0) {
final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mSidePaddings;
final float stackEndHeight = Math.max(0f,
- getHeight() - getEmptyBottomMargin() - stackY);
+ getHeight() - getEmptyBottomMargin() - mTopPadding);
mAmbientState.setStackEndHeight(stackEndHeight);
mAmbientState.setStackHeight(
MathUtils.lerp(stackEndHeight * StackScrollAlgorithm.START_FRACTION,
@@ -4278,6 +4269,13 @@
+ mGapHeight;
}
+ /**
+ * @return the padding after the media header on the lockscreen
+ */
+ public int getPaddingAfterMedia() {
+ return mGapHeight + mPaddingBetweenElements;
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getEmptyShadeViewHeight() {
return mEmptyShadeView.getHeight();
@@ -4933,12 +4931,6 @@
getChildCount() - offsetFromEnd);
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setNotificationPanelController(
- NotificationPanelViewController notificationPanelViewController) {
- mNotificationPanelController = notificationPanelViewController;
- }
-
/**
* Set how far the wake up is when waking up from pulsing. This is a height and will adjust the
* notification positions accordingly.
@@ -5155,6 +5147,16 @@
}
/**
+ * Sets the extra top inset for the full shade transition. This is needed to compensate for
+ * media transitioning to quick settings
+ */
+ public void setExtraTopInsetForFullShadeTransition(float inset) {
+ mExtraTopInsetForFullShadeTransition = inset;
+ updateStackPosition();
+ requestChildrenUpdate();
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5526,108 +5528,10 @@
}
}
- public void setKeyguardMediaControllorVisible(boolean keyguardMediaControllorVisible) {
- mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
- }
-
void resetCheckSnoozeLeavebehind() {
setCheckForLeaveBehind(true);
}
- // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private final DragDownCallback mDragDownCallback = new DragDownCallback() {
-
- @Override
- public boolean canDragDown() {
- return mStatusBarState == StatusBarState.KEYGUARD
- && (mController.hasActiveNotifications() || mKeyguardMediaControllorVisible)
- || mController.isInLockedDownShade();
- }
-
- /* Only ever called as a consequence of a lockscreen expansion gesture. */
- @Override
- public void onDraggedDown(View startingChild, int dragLengthY) {
- boolean canDragDown =
- mController.hasActiveNotifications() || mKeyguardMediaControllorVisible;
- if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_SHADE,
- (int) (dragLengthY / mDisplayMetrics.density),
- 0 /* velocityDp - N/A */);
- mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN);
-
- if (!mAmbientState.isDozing() || startingChild != null) {
- // We have notifications, go to locked shade.
- mShadeController.goToLockedShade(startingChild);
- if (startingChild instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
- row.onExpandedByGesture(true /* drag down is always an open */);
- }
- }
- } else if (mController.isInLockedDownShade()) {
- mStatusbarStateController.setLeaveOpenOnKeyguardHide(true);
- mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */,
- null /* cancelRunnable */, false /* afterKeyguardGone */);
- }
- }
-
- @Override
- public void onDragDownReset() {
- setDimmed(true /* dimmed */, true /* animated */);
- resetScrollPosition();
- resetCheckSnoozeLeavebehind();
- }
-
- @Override
- public void onCrossedThreshold(boolean above) {
- setDimmed(!above /* dimmed */, true /* animate */);
- }
-
- @Override
- public void onTouchSlopExceeded() {
- cancelLongPress();
- mController.checkSnoozeLeavebehind();
- }
-
- @Override
- public void setEmptyDragAmount(float amount) {
- mNotificationPanelController.setEmptyDragAmount(amount);
- }
-
- @Override
- public boolean isFalsingCheckNeeded() {
- return mStatusBarState == StatusBarState.KEYGUARD;
- }
-
- @Override
- public boolean isDragDownEnabledForView(ExpandableView view) {
- if (isDragDownAnywhereEnabled()) {
- return true;
- }
- if (mController.isInLockedDownShade()) {
- if (view == null) {
- // Dragging down is allowed in general
- return true;
- }
- if (view instanceof ExpandableNotificationRow) {
- // Only drag down on sensitive views, otherwise the ExpandHelper will take this
- return ((ExpandableNotificationRow) view).getEntry().isSensitive();
- }
- }
- return false;
- }
-
- @Override
- public boolean isDragDownAnywhereEnabled() {
- return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
- && !mKeyguardBypassEnabledProvider.getBypassEnabled();
- }
- };
-
- public DragDownCallback getDragDownCallback() { return mDragDownCallback; }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private final HeadsUpTouchHelper.Callback mHeadsUpCallback = new HeadsUpTouchHelper.Callback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index f7eb574..0d42428 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -31,6 +31,7 @@
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.canChildBeDismissed;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -38,6 +39,7 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
+import android.util.MathUtils;
import android.util.Pair;
import android.view.Display;
import android.view.LayoutInflater;
@@ -59,6 +61,7 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -70,6 +73,7 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -107,7 +111,6 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -168,6 +171,7 @@
// TODO: StatusBar should be encapsulated behind a Controller
private final StatusBar mStatusBar;
private final SectionHeaderController mSilentHeaderController;
+ private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private NotificationStackScrollLayout mView;
private boolean mFadeNotificationsOnDismiss;
@@ -181,6 +185,9 @@
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
+ private int mTotalDistanceForFullShadeTransition;
+ private int mTotalExtraMediaInsetFullShadeTransition;
+
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() {
@@ -240,8 +247,20 @@
public void onThemeChanged() {
updateFooter();
}
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ updateResources();
+ }
};
+ private void updateResources() {
+ mTotalExtraMediaInsetFullShadeTransition = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_transition_extra_media_inset);
+ mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_transition_distance);
+ }
+
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -571,6 +590,7 @@
NotifPipeline notifPipeline,
NotifCollection notifCollection,
NotificationEntryManager notificationEntryManager,
+ LockscreenShadeTransitionController lockscreenShadeTransitionController,
IStatusBarService iStatusBarService,
UiEventLogger uiEventLogger,
ForegroundServiceDismissalFeatureController fgFeatureController,
@@ -592,6 +612,7 @@
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
+ mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mResources = resources;
@@ -624,6 +645,7 @@
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
mShadeController = shadeController;
+ updateResources();
}
public void attach(NotificationStackScrollLayout view) {
@@ -676,6 +698,8 @@
mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
+ mLockscreenShadeTransitionController.setStackScroller(this);
+
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
mFadeNotificationsOnDismiss = // TODO: this should probably be injected directly
@@ -705,7 +729,6 @@
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
mKeyguardMediaController.setVisibilityChangedListener(visible -> {
- mView.setKeyguardMediaControllorVisible(visible);
if (visible) {
mView.generateAddAnimation(
mKeyguardMediaController.getSinglePaneContainer(),
@@ -1203,11 +1226,6 @@
mView.runAfterAnimationFinished(r);
}
- public void setNotificationPanelController(
- NotificationPanelViewController notificationPanelViewController) {
- mView.setNotificationPanelController(notificationPanelViewController);
- }
-
public void setShelfController(NotificationShelfController notificationShelfController) {
mView.setShelfController(notificationShelfController);
}
@@ -1275,7 +1293,10 @@
NotificationLogger.getNotificationLocation(entry)));
}
- boolean hasActiveNotifications() {
+ /**
+ * @return if the shade has currently any active notifications.
+ */
+ public boolean hasActiveNotifications() {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
return !mNotifPipeline.getShadeList().isEmpty();
} else {
@@ -1354,11 +1375,60 @@
}
}
+ /**
+ * @return the expand helper callback.
+ */
+ public ExpandHelper.Callback getExpandHelperCallback() {
+ return mView.getExpandHelperCallback();
+ }
+
+ /**
+ * @return If the shade is in the locked down shade.
+ */
public boolean isInLockedDownShade() {
return mDynamicPrivacyController.isInLockedDownShade();
}
/**
+ * Set the dimmed state for all of the notification views.
+ */
+ public void setDimmed(boolean dimmed, boolean animate) {
+ mView.setDimmed(dimmed, animate);
+ }
+
+ /**
+ * @return the inset during the full shade transition, that needs to be added to the position
+ * of the quick settings edge. This is relevant for media, that is transitioning
+ * from the keyguard host to the quick settings one.
+ */
+ public int getFullShadeTransitionInset() {
+ MediaHeaderView view = mKeyguardMediaController.getSinglePaneContainer();
+ if (view == null || view.getHeight() == 0
+ || mStatusBarStateController.getState() != KEYGUARD) {
+ return 0;
+ }
+ return view.getHeight() + mView.getPaddingAfterMedia();
+ }
+
+ /**
+ * Set the amount of pixels we have currently dragged down if we're transitioning to the full
+ * shade. 0.0f means we're not transitioning yet.
+ */
+ public void setTransitionToFullShadeAmount(float amount) {
+ float extraTopInset;
+ MediaHeaderView view = mKeyguardMediaController.getSinglePaneContainer();
+ if (view == null || view.getHeight() == 0
+ || mStatusBarStateController.getState() != KEYGUARD) {
+ extraTopInset = 0;
+ } else {
+ extraTopInset = MathUtils.saturate(amount / mTotalDistanceForFullShadeTransition);
+ extraTopInset = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(extraTopInset);
+ extraTopInset = extraTopInset * mTotalExtraMediaInsetFullShadeTransition;
+ }
+ mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
+ }
+
+ /**
* Enum for UiEvent logged from this class
*/
enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index b2d39a9..e931ec4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -225,6 +225,8 @@
// already accounted for by the top padding and doesn't need an additional adaption
scrollY = Math.max(0, scrollY);
state.scrollY = (int) (scrollY + bottomOverScroll);
+ state.mCurrentYPosition = -state.scrollY;
+ state.mCurrentExpandedYPosition = -state.scrollY;
//now init the visible children and update paddings
int childCount = hostView.getChildCount();
@@ -321,14 +323,14 @@
*/
private void updatePositionsForState(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
- // The y coordinate of the current child.
- float currentYPosition = -algorithmState.scrollY;
if (!ambientState.isOnKeyguard()) {
- currentYPosition += mNotificationScrimPadding;
+ algorithmState.mCurrentYPosition += mNotificationScrimPadding;
+ algorithmState.mCurrentExpandedYPosition += mNotificationScrimPadding;
}
+
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
- currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition);
+ updateChild(i, algorithmState, ambientState);
}
}
@@ -348,14 +350,14 @@
StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
- final boolean isShowingShelf = ambientState.getShelf() != null
+ final boolean showingShelf = ambientState.getShelf() != null
&& algorithmState.firstViewInShelf != null;
- final float stackHeight = ambientState.getStackHeight()
- - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f);
+ final float shelfHeight = showingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f;
+ final float scrimPadding = ambientState.isOnKeyguard() ? 0 : mNotificationScrimPadding;
- float stackEndHeight = ambientState.getStackEndHeight()
- - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f);
+ final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
+ final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
return stackHeight / stackEndHeight;
}
@@ -368,17 +370,11 @@
* {@link StackScrollAlgorithmState#visibleChildren}.
* @param algorithmState The overall output state of the algorithm.
* @param ambientState The input state provided to the algorithm.
- * @param currentYPosition The Y position of the current pass of the algorithm. For a forward
- * pass, this should be the top of the child; for a reverse pass, the
- * bottom of the child.
- * @return The Y position after laying out the child. This will be the {@code currentYPosition}
- * for the next call to this method, after adjusting for any gaps between children.
*/
- protected float updateChild(
+ protected void updateChild(
int i,
StackScrollAlgorithmState algorithmState,
- AmbientState ambientState,
- float currentYPosition) {
+ AmbientState ambientState) {
ExpandableView view = algorithmState.visibleChildren.get(i);
ExpandableViewState viewState = view.getViewState();
@@ -407,10 +403,11 @@
ambientState.getSectionProvider(), i,
view, getPreviousView(i, algorithmState));
if (applyGapHeight) {
- currentYPosition += expansionFraction * mGapHeight;
+ algorithmState.mCurrentYPosition += expansionFraction * mGapHeight;
+ algorithmState.mCurrentExpandedYPosition += mGapHeight;
}
- viewState.yTranslation = currentYPosition;
+ viewState.yTranslation = algorithmState.mCurrentYPosition;
if (view instanceof SectionHeaderView) {
// Add padding before sections for overscroll effect.
viewState.yTranslation += expansionFraction * ambientState.getSectionPadding();
@@ -419,12 +416,11 @@
if (view instanceof FooterView) {
final boolean isShelfShowing = algorithmState.firstViewInShelf != null;
- final float footerEnd = viewState.yTranslation + view.getIntrinsicHeight();
- final boolean noSpaceForFooter = footerEnd > ambientState.getStackHeight();
+ final float footerEnd = algorithmState.mCurrentExpandedYPosition
+ + view.getIntrinsicHeight();
+ final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
- viewState.hidden = isShelfShowing
- || (!ambientState.isExpansionChanging() && noSpaceForFooter);
-
+ viewState.hidden = isShelfShowing || noSpaceForFooter;
} else if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
// Show all views. Views below the shelf will later be clipped (essentially hidden)
@@ -459,14 +455,16 @@
maxViewHeight = algorithmState.viewHeightBeforeShelf;
}
}
- viewState.height = (int) MathUtils.lerp(maxViewHeight * START_FRACTION, maxViewHeight,
- expansionFraction);
+ viewState.height = (int) (maxViewHeight * expansionFraction);
}
- currentYPosition += viewState.height + expansionFraction * mPaddingBetweenElements;
- setLocation(view.getViewState(), currentYPosition, i);
+ algorithmState.mCurrentYPosition += viewState.height
+ + expansionFraction * mPaddingBetweenElements;
+ algorithmState.mCurrentExpandedYPosition += view.getIntrinsicHeight()
+ + mPaddingBetweenElements;
+
+ setLocation(view.getViewState(), algorithmState.mCurrentYPosition, i);
viewState.yTranslation += ambientState.getStackY();
- return currentYPosition;
}
/**
@@ -739,6 +737,18 @@
* The children from the host view which are not gone.
*/
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<>();
+
+ /**
+ * Y position of the current view during updating children
+ * with expansion factor applied.
+ */
+ private int mCurrentYPosition;
+
+ /**
+ * Y position of the current view during updating children
+ * without applying the expansion factor.
+ */
+ private int mCurrentExpandedYPosition;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 16863f6..20e6f60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -114,7 +114,8 @@
public static final int MODE_ONLY_WAKE = 4;
/**
- * Mode in which fingerprint unlocks the device.
+ * Mode in which fingerprint unlocks the device or passive auth (ie face auth) unlocks the
+ * device while being requested when keyguard is occluded.
*/
public static final int MODE_UNLOCK_COLLAPSING = 5;
@@ -355,8 +356,10 @@
Optional.ofNullable(BiometricUiEvent.SUCCESS_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
.ifPresent(UI_EVENT_LOGGER::log);
- boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
- biometricSourceType, isStrongBiometric);
+ boolean unlockAllowed =
+ mKeyguardStateController.isOccluded()
+ || mKeyguardBypassController.onBiometricAuthenticated(
+ biometricSourceType, isStrongBiometric);
if (unlockAllowed) {
mKeyguardViewMediator.userActivity();
startWakeAndUnlock(biometricSourceType, isStrongBiometric);
@@ -581,6 +584,9 @@
if (unlockingAllowed && deviceDreaming) {
return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE;
}
+ if (unlockingAllowed && mKeyguardStateController.isOccluded()) {
+ return MODE_UNLOCK_COLLAPSING;
+ }
if (mKeyguardViewController.isShowing()) {
if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) {
if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index c5a155e..684760e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -81,7 +81,7 @@
private NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
- private ViewGroup mOngoingCallChip;
+ private View mOngoingCallChip;
private View mNotificationIconAreaInner;
private View mCenteredIconArea;
private int mDisabled1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index c64b893..7f919b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -39,6 +39,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -48,11 +49,13 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
+import android.provider.Settings;
import android.service.media.CameraPrewarmService;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -94,6 +97,7 @@
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.concurrent.Executor;
@@ -189,6 +193,8 @@
private int mBurnInYOffset;
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private ContentObserver mWalletPreferenceObserver;
+ private SecureSettings mSecureSettings;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -251,7 +257,6 @@
super.onFinishInflate();
mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext),
new ActivityIntentHelper(mContext));
- mPreviewContainer = findViewById(R.id.preview_container);
mOverlayContainer = findViewById(R.id.overlay_container);
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.left_button);
@@ -268,7 +273,6 @@
mKeyguardStateController.addCallback(this);
setClipChildren(false);
setClipToPadding(false);
- inflateCameraPreview();
mRightAffordanceView.setOnClickListener(this);
mLeftAffordanceView.setOnClickListener(this);
initAccessibility();
@@ -276,13 +280,21 @@
mFlashlightController = Dependency.get(FlashlightController.class);
mAccessibilityController = Dependency.get(AccessibilityController.class);
mActivityIntentHelper = new ActivityIntentHelper(getContext());
- updateLeftAffordance();
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
}
+ /**
+ * Set the container where the previews are rendered.
+ */
+ public void setPreviewContainer(ViewGroup previewContainer) {
+ mPreviewContainer = previewContainer;
+ inflateCameraPreview();
+ updateLeftAffordance();
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -319,6 +331,10 @@
mLeftExtension.destroy();
getContext().unregisterReceiver(mDevicePolicyReceiver);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+
+ if (mWalletPreferenceObserver != null) {
+ mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
+ }
}
private void initAccessibility() {
@@ -560,7 +576,6 @@
}
});
} else {
-
// We need to delay starting the activity because ResolverActivity finishes itself if
// launched behind lockscreen.
mActivityStarter.startActivity(intent, false /* dismissShade */,
@@ -680,6 +695,9 @@
}
private void inflateCameraPreview() {
+ if (mPreviewContainer == null) {
+ return;
+ }
View previewBefore = mCameraPreview;
boolean visibleBefore = false;
if (previewBefore != null) {
@@ -697,6 +715,9 @@
}
private void updateLeftPreview() {
+ if (mPreviewContainer == null) {
+ return;
+ }
View previewBefore = mLeftPreview;
if (previewBefore != null) {
mPreviewContainer.removeView(previewBefore);
@@ -914,15 +935,40 @@
/**
* Initialize the wallet feature, only enabling if the feature is enabled within the platform.
*/
- public void initWallet(QuickAccessWalletClient client, Executor uiExecutor, boolean enabled) {
+ public void initWallet(QuickAccessWalletClient client, Executor uiExecutor,
+ SecureSettings secureSettings) {
mQuickAccessWalletClient = client;
- mWalletEnabled = enabled && client.isWalletFeatureAvailable();
+ mSecureSettings = secureSettings;
+ setupWalletPreferenceObserver();
+ updateWalletPreference();
+
mUiExecutor = uiExecutor;
queryWalletCards();
updateWalletVisibility();
}
+ private void setupWalletPreferenceObserver() {
+ if (mWalletPreferenceObserver == null) {
+ mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mUiExecutor.execute(() -> updateWalletPreference());
+ }
+ };
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
+ false /* notifyForDescendants */,
+ mWalletPreferenceObserver);
+ }
+ }
+
+ private void updateWalletPreference() {
+ mWalletEnabled = mQuickAccessWalletClient.isWalletFeatureAvailable()
+ && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
+ }
+
private void queryWalletCards() {
if (!mWalletEnabled || mUiExecutor == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 069c197..f4710f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -140,7 +140,7 @@
*/
private float mQsExpansion;
- private float mEmptyDragAmount;
+ private float mOverStretchAmount;
/**
* Setting if bypass is enabled. If true the clock should always be positioned like it's dark
@@ -181,7 +181,7 @@
int notificationStackHeight, float panelExpansion, int parentHeight,
int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY,
int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
- float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
+ float overStrechAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
@@ -196,7 +196,7 @@
mHasCustomClock = hasCustomClock;
mHasVisibleNotifs = hasVisibleNotifs;
mDarkAmount = dark;
- mEmptyDragAmount = emptyDragAmount;
+ mOverStretchAmount = overStrechAmount;
mBypassEnabled = bypassEnabled;
mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
mQsExpansion = qsExpansion;
@@ -301,7 +301,7 @@
}
clockYDark = clockY + burnInPreventionOffsetY() + shift;
}
- return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
+ return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount);
}
private int getUserSwitcherY(float panelExpansion) {
@@ -312,7 +312,7 @@
float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion);
float userSwitchY = MathUtils.lerp(userSwitchYBouncer, userSwitchYRegular, shadeExpansion);
- return (int) (userSwitchY + mEmptyDragAmount);
+ return (int) (userSwitchY + mOverStretchAmount);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 12dec14..9d8a9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -114,6 +114,7 @@
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -151,6 +152,7 @@
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.Utils;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
@@ -207,7 +209,6 @@
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
- private final ExpansionCallback mExpansionCallback = new ExpansionCallback();
private final BiometricUnlockController mBiometricUnlockController;
private final NotificationPanelView mView;
private final VibratorHelper mVibratorHelper;
@@ -312,10 +313,12 @@
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
private final int mMaxKeyguardNotifications;
+ private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private boolean mShouldUseSplitNotificationShade;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
+ private ViewGroup mPreviewContainer;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
@@ -365,7 +368,7 @@
private int mStatusBarMinHeight;
private int mStatusBarHeaderHeightKeyguard;
private int mNotificationsHeaderCollideDistance;
- private float mEmptyDragAmount;
+ private float mOverStretchAmount;
private float mDownX;
private float mDownY;
private int mDisplayCutoutTopInset = 0; // in pixels
@@ -481,7 +484,6 @@
private final CommandQueue mCommandQueue;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
- private final ShadeController mShadeController;
private final MediaDataManager mMediaDataManager;
private NotificationShadeDepthController mDepthController;
private int mDisplayId;
@@ -505,6 +507,39 @@
private float mSectionPadding;
/**
+ * The amount of progress we are currently in if we're transitioning to the full shade.
+ * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
+ * shade. This value can also go beyond 1.1 when we're overshooting!
+ */
+ private float mTransitioningToFullShadeProgress;
+
+ /**
+ * Position of the qs bottom during the full shade transition. This is needed as the toppadding
+ * can change during state changes, which makes it much harder to do animations
+ */
+ private int mTransitionToFullShadeQSPosition;
+
+ /**
+ * Distance that the full shade transition takes in order for qs to fully transition to the
+ * shade.
+ */
+ private int mDistanceForQSFullShadeTransition;
+
+ /**
+ * The maximum overshoot allowed for the top padding for the full shade transition
+ */
+ private int mMaxOverscrollAmountForDragDown;
+
+ /**
+ * Should we animate the next bounds update
+ */
+ private boolean mAnimateNextNotificationBounds;
+ /**
+ * The delay for the next bounds animation
+ */
+ private long mNotificationBoundsAnimationDelay;
+
+ /**
* Is this a collapse that started on the panel where we should allow the panel to intercept
*/
private boolean mIsPanelCollapseOnQQS;
@@ -521,6 +556,16 @@
private boolean mDelayShowingKeyguardStatusBar;
private boolean mAnimatingQS;
+
+ /**
+ * The end bounds of a clipping animation.
+ */
+ private final Rect mQsClippingAnimationEndBounds = new Rect();
+
+ /**
+ * The animator for the qs clipping bounds.
+ */
+ private ValueAnimator mQsClippingAnimation = null;
private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private int mOldLayoutDirection;
private NotificationShelfController mNotificationShelfController;
@@ -530,6 +575,7 @@
private final QuickAccessWalletClient mQuickAccessWalletClient;
private final Executor mUiExecutor;
+ private final SecureSettings mSecureSettings;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
private KeyguardMediaController mKeyguardMediaController;
@@ -569,7 +615,7 @@
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
- FalsingCollector falsingCollector, ShadeController shadeController,
+ FalsingCollector falsingCollector,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
@@ -591,6 +637,7 @@
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
+ LockscreenShadeTransitionController lockscreenShadeTransitionController,
QSDetailDisplayer qsDetailDisplayer,
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
@@ -605,7 +652,8 @@
QuickAccessWalletClient quickAccessWalletClient,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
- @Main Executor uiExecutor) {
+ @Main Executor uiExecutor,
+ SecureSettings secureSettings) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
@@ -657,6 +705,7 @@
mMediaDataManager = mediaDataManager;
mQuickAccessWalletClient = quickAccessWalletClient;
mUiExecutor = uiExecutor;
+ mSecureSettings = secureSettings;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -677,6 +726,8 @@
}
}
};
+ mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
+ lockscreenShadeTransitionController.setNotificationPanelController(this);
mKeyguardStateController.addCallback(keyguardMonitorCallback);
DynamicPrivacyControlListener
dynamicPrivacyControlListener =
@@ -690,7 +741,6 @@
});
mBottomAreaShadeAlphaAnimator.setDuration(160);
mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mShadeController = shadeController;
mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
@@ -749,14 +799,22 @@
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area);
+ mPreviewContainer = mView.findViewById(R.id.preview_container);
+ mKeyguardBottomArea.setPreviewContainer(mPreviewContainer);
mLastOrientation = mResources.getConfiguration().orientation;
initBottomArea();
mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController);
mQsFrame = mView.findViewById(R.id.qs_frame);
- mPulseExpansionHandler.setUp(
- mNotificationStackScrollLayoutController, mExpansionCallback, mShadeController);
+ mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController,
+ amount -> {
+ float progress = amount / mView.getHeight();
+ float overstretch = Interpolators.getOvershootInterpolation(progress,
+ (float) mMaxOverscrollAmountForDragDown / mView.getHeight(),
+ 0.2f);
+ setOverStrechAmount(overstretch);
+ });
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
@@ -812,6 +870,10 @@
com.android.internal.R.dimen.status_bar_height);
mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize(
R.dimen.heads_up_status_bar_padding);
+ mDistanceForQSFullShadeTransition = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_transition_distance);
+ mMaxOverscrollAmountForDragDown = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_max_top_overshoot);
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
mScreenCornerRadius = mResources.getDimensionPixelSize(
@@ -989,6 +1051,7 @@
mKeyguardBottomArea = (KeyguardBottomAreaView) mLayoutInflater.inflate(
R.layout.keyguard_bottom_area, mView, false);
mKeyguardBottomArea.initFrom(oldBottomArea);
+ mKeyguardBottomArea.setPreviewContainer(mPreviewContainer);
mView.addView(mKeyguardBottomArea, index);
initBottomArea();
mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
@@ -1033,8 +1096,10 @@
mKeyguardBottomArea.setStatusBar(mStatusBar);
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
- mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor,
- mFeatureFlags.isQuickAccessWalletEnabled());
+
+ if (mFeatureFlags.isQuickAccessWalletEnabled()) {
+ mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor, mSecureSettings);
+ }
}
private void updateMaxDisplayedNotifications(boolean recompute) {
@@ -1108,58 +1173,28 @@
* showing.
*/
private void positionClockAndNotifications() {
+ positionClockAndNotifications(false /* forceUpdate */);
+ }
+
+ /**
+ * Positions the clock and notifications dynamically depending on how many notifications are
+ * showing.
+ *
+ * @param forceClockUpdate Should the clock be updated even when not on keyguard
+ */
+ private void positionClockAndNotifications(boolean forceClockUpdate) {
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
- boolean animateClock = animate || mAnimateNextPositionUpdate;
int stackScrollerPadding;
- if (mBarState != KEYGUARD) {
+ boolean onKeyguard = isOnKeyguard();
+ if (onKeyguard || forceClockUpdate) {
+ updateClockAppearance();
+ }
+ if (!onKeyguard) {
stackScrollerPadding = getUnlockedStackScrollerPadding();
} else {
- int totalHeight = mView.getHeight();
- int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
- int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
- int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
- boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
- final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
- .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
- mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
- int userIconHeight = mKeyguardQsUserSwitchController != null
- ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
- mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
- totalHeight - bottomPadding,
- mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
- getExpandedFraction(),
- totalHeight,
- mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1
- ? mKeyguardStatusViewController.getHeight()
- : (int) (mKeyguardStatusViewController.getHeight()
- - mShelfHeight / 2.0f - mDarkIconSize / 2.0f),
- userIconHeight,
- clockPreferredY, userSwitcherPreferredY, hasCustomClock(),
- hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
- bypassEnabled, getUnlockedStackScrollerPadding(),
- getQsExpansionFraction(),
- mDisplayCutoutTopInset,
- shouldUseSplitNotificationShade(mFeatureFlags, mResources));
- mClockPositionAlgorithm.run(mClockPositionResult);
- mKeyguardStatusViewController.updatePosition(
- mClockPositionResult.clockX, mClockPositionResult.clockY,
- mClockPositionResult.clockScale, animateClock);
- if (mKeyguardQsUserSwitchController != null) {
- mKeyguardQsUserSwitchController.updatePosition(
- mClockPositionResult.clockX,
- mClockPositionResult.userSwitchY,
- animateClock);
- }
- if (mKeyguardUserSwitcherController != null) {
- mKeyguardUserSwitcherController.updatePosition(
- mClockPositionResult.clockX,
- mClockPositionResult.userSwitchY,
- animateClock);
- }
- updateNotificationTranslucency();
- updateClock();
stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
}
+
mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
@@ -1169,6 +1204,60 @@
mAnimateNextPositionUpdate = false;
}
+ private void updateClockAppearance() {
+ int totalHeight = mView.getHeight();
+ int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
+ int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
+ int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
+ boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
+ final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
+ .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
+ mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
+ int userIconHeight = mKeyguardQsUserSwitchController != null
+ ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
+ float expandedFraction =
+ mKeyguardStatusViewController.isAnimatingScreenOffFromUnlocked() ? 1.0f
+ : getExpandedFraction();
+ float darkamount = mKeyguardStatusViewController.isAnimatingScreenOffFromUnlocked() ? 1.0f
+ : mInterpolatedDarkAmount;
+ mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
+ totalHeight - bottomPadding,
+ mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
+ expandedFraction,
+ totalHeight,
+ mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1
+ ? mKeyguardStatusViewController.getHeight()
+ : (int) (mKeyguardStatusViewController.getHeight()
+ - mShelfHeight / 2.0f - mDarkIconSize / 2.0f),
+ userIconHeight,
+ clockPreferredY, userSwitcherPreferredY, hasCustomClock(),
+ hasVisibleNotifications, darkamount, mOverStretchAmount,
+ bypassEnabled, getUnlockedStackScrollerPadding(),
+ computeQsExpansionFraction(),
+ mDisplayCutoutTopInset,
+ shouldUseSplitNotificationShade(mFeatureFlags, mResources));
+ mClockPositionAlgorithm.run(mClockPositionResult);
+ boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
+ boolean animateClock = animate || mAnimateNextPositionUpdate;
+ mKeyguardStatusViewController.updatePosition(
+ mClockPositionResult.clockX, mClockPositionResult.clockY,
+ mClockPositionResult.clockScale, animateClock);
+ if (mKeyguardQsUserSwitchController != null) {
+ mKeyguardQsUserSwitchController.updatePosition(
+ mClockPositionResult.clockX,
+ mClockPositionResult.userSwitchY,
+ animateClock);
+ }
+ if (mKeyguardUserSwitcherController != null) {
+ mKeyguardUserSwitcherController.updatePosition(
+ mClockPositionResult.clockX,
+ mClockPositionResult.userSwitchY,
+ animateClock);
+ }
+ updateNotificationTranslucency();
+ updateClock();
+ }
+
/**
* @return the padding of the stackscroller when unlocked
*/
@@ -1600,7 +1689,7 @@
private boolean flingExpandsQs(float vel) {
if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- return getQsExpansionFraction() > 0.5f;
+ return computeQsExpansionFraction() > 0.5f;
} else {
return vel > 0;
}
@@ -1613,7 +1702,7 @@
return !mQsTouchAboveFalsingThreshold;
}
- private float getQsExpansionFraction() {
+ private float computeQsExpansionFraction() {
return Math.min(
1f, (mQsExpansionHeight - mQsMinExpansionHeight) / (mQsMaxExpansionHeight
- mQsMinExpansionHeight));
@@ -1838,7 +1927,7 @@
mQsTracking = false;
mTrackingPointer = -1;
trackMovement(event);
- float fraction = getQsExpansionFraction();
+ float fraction = computeQsExpansionFraction();
if (fraction != 0f || y >= mInitialTouchY) {
flingQsWithCurrentVelocity(y,
event.getActionMasked() == MotionEvent.ACTION_CANCEL);
@@ -2044,18 +2133,19 @@
protected void updateQsExpansion() {
if (mQs == null) return;
- float qsExpansionFraction = getQsExpansionFraction();
+ float qsExpansionFraction = computeQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
+ setQSClippingBounds();
mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
private Runnable mOnStackYChanged = () -> {
if (mQs != null) {
- setNotificationBounds();
+ setQSClippingBounds();
}
};
@@ -2063,57 +2153,121 @@
* Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
* and QS state.
*/
- private void setNotificationBounds() {
+ private void setQSClippingBounds() {
int top = 0;
int bottom = 0;
int left = 0;
int right = 0;
- final int qsPanelBottomY = calculateQsBottomPosition(getQsExpansionFraction());
- final boolean visible = (getQsExpansionFraction() > 0 || qsPanelBottomY > 0)
+ final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
+ final boolean visible = (computeQsExpansionFraction() > 0 || qsPanelBottomY > 0)
&& !mShouldUseSplitNotificationShade;
- final float notificationTop = mAmbientState.getStackY() - mAmbientState.getScrollY();
setQsExpansionEnabled(mAmbientState.getScrollY() == 0);
- int radius = mScrimCornerRadius;
if (!mShouldUseSplitNotificationShade) {
- top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
- : notificationTop);
+ if (mTransitioningToFullShadeProgress > 0.0f) {
+ // If we're transitioning, let's use the actual value. The else case
+ // can be wrong during transitions when waiting for the keyguard to unlock
+ top = mTransitionToFullShadeQSPosition;
+ } else {
+ float notificationTop = getQSEdgePosition();
+ top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
+ : notificationTop);
+ }
bottom = getView().getBottom();
left = getView().getLeft();
right = getView().getRight();
- radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
- Math.min(top / (float) mScrimCornerRadius, 1f));
} else if (qsPanelBottomY > 0) { // so bounds are empty on lockscreen
top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
bottom = mNotificationStackScrollLayoutController.getHeight();
left = mNotificationStackScrollLayoutController.getLeft();
right = mNotificationStackScrollLayoutController.getRight();
}
+ applyQSClippingBounds(left, top, right, bottom, visible);
+ }
- // Fancy clipping for quick settings
- if (mQs != null) {
- mQs.setFancyClipping(top, bottom, radius, visible);
+ private void applyQSClippingBounds(int left, int top, int right, int bottom,
+ boolean visible) {
+ if (!mAnimateNextNotificationBounds || mKeyguardStatusAreaClipBounds.isEmpty()) {
+ if (mQsClippingAnimation != null) {
+ // update the end position of the animator
+ mQsClippingAnimationEndBounds.set(left, top, right, bottom);
+ } else {
+ applyQSClippingImmediately(left, top, right, bottom, visible);
+ }
+ } else {
+ mQsClippingAnimationEndBounds.set(left, top, right, bottom);
+ final int startLeft = mKeyguardStatusAreaClipBounds.left;
+ final int startTop = mKeyguardStatusAreaClipBounds.top;
+ final int startRight = mKeyguardStatusAreaClipBounds.right;
+ final int startBottom = mKeyguardStatusAreaClipBounds.bottom;
+ mQsClippingAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mQsClippingAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mQsClippingAnimation.setDuration(
+ StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+ mQsClippingAnimation.setStartDelay(mNotificationBoundsAnimationDelay);
+ mQsClippingAnimation.addUpdateListener(animation -> {
+ float fraction = animation.getAnimatedFraction();
+ int animLeft = (int) MathUtils.lerp(startLeft,
+ mQsClippingAnimationEndBounds.left, fraction);
+ int animTop = (int) MathUtils.lerp(startTop,
+ mQsClippingAnimationEndBounds.top, fraction);
+ int animRight = (int) MathUtils.lerp(startRight,
+ mQsClippingAnimationEndBounds.right, fraction);
+ int animBottom = (int) MathUtils.lerp(startBottom,
+ mQsClippingAnimationEndBounds.bottom, fraction);
+ applyQSClippingImmediately(animLeft, animTop, animRight, animBottom,
+ visible /* visible */);
+ });
+ mQsClippingAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mQsClippingAnimation = null;
+ }
+ });
+ mQsClippingAnimation.start();
}
+ mAnimateNextNotificationBounds = false;
+ mNotificationBoundsAnimationDelay = 0;
+ }
+
+ private void applyQSClippingImmediately(int left, int top, int right, int bottom,
+ boolean visible) {
+ // Fancy clipping for quick settings
+ int radius = mScrimCornerRadius;
if (!mShouldUseSplitNotificationShade) {
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
mKeyguardStatusViewController.setClipBounds(visible
? mKeyguardStatusAreaClipBounds : null);
+ radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
+ Math.min(top / (float) mScrimCornerRadius, 1f));
+ }
+ if (mQs != null) {
+ mQs.setFancyClipping(top, bottom, radius, visible);
}
mScrimController.setNotificationsBounds(left, top, right, bottom);
mScrimController.setScrimCornerRadius(radius);
}
+ private float getQSEdgePosition() {
+ // TODO: replace StackY with unified calculation
+ return mAmbientState.getStackY() - mAmbientState.getScrollY();
+ }
+
private int calculateQsBottomPosition(float qsExpansionFraction) {
- int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
- if (qsExpansionFraction != 0.0) {
- qsBottomY = (int) MathUtils.lerp(
- qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
+ if (mTransitioningToFullShadeProgress > 0.0f) {
+ return mTransitionToFullShadeQSPosition;
+ } else {
+ int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
+ if (qsExpansionFraction != 0.0) {
+ qsBottomY = (int) MathUtils.lerp(
+ qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
+ }
+ // to account for shade overshooting animation, see setSectionPadding method
+ if (mSectionPadding > 0) qsBottomY += mSectionPadding;
+ return qsBottomY;
}
- // to account for shade overshooting animation, see setSectionPadding method
- if (mSectionPadding > 0) qsBottomY += mSectionPadding;
- return qsBottomY;
}
private String determineAccessibilityPaneTitle() {
@@ -2157,7 +2311,7 @@
// from a scrolled quick settings.
return MathUtils.lerp((float) getKeyguardNotificationStaticPadding(),
(float) (mQsMaxExpansionHeight + mQsNotificationTopPadding),
- getQsExpansionFraction());
+ computeQsExpansionFraction());
} else {
return mQsExpansionHeight + mQsNotificationTopPadding;
}
@@ -2194,15 +2348,65 @@
}
}
-
private void updateQSPulseExpansion() {
if (mQs != null) {
- mQs.setShowCollapsedOnKeyguard(
+ mQs.setPulseExpanding(
mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()
&& mNotificationStackScrollLayoutController.isPulseExpanding());
}
}
+ /**
+ * Set the amount of pixels we have currently dragged down if we're transitioning to the full
+ * shade. 0.0f means we're not transitioning yet.
+ */
+ public void setTransitionToFullShadeAmount(float pxAmount, boolean animate, long delay) {
+ mAnimateNextNotificationBounds = animate && !mShouldUseSplitNotificationShade;
+ mNotificationBoundsAnimationDelay = delay;
+ float progress = MathUtils.saturate(pxAmount / mView.getHeight());
+
+ float endPosition = 0;
+ if (pxAmount > 0.0f) {
+ if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() == 0
+ && !mMediaDataManager.hasActiveMedia()) {
+ // No notifications are visible, let's animate to the height of qs instead
+ if (mQs != null) {
+ // Let's interpolate to the header height
+ endPosition = mQs.getHeader().getHeight();
+ }
+ } else {
+ // Interpolating to the new bottom edge position!
+ endPosition = getQSEdgePosition() - mOverStretchAmount;
+
+ // If we have media, we need to put the boundary below it, as the media header
+ // still uses the space during the transition.
+ endPosition +=
+ mNotificationStackScrollLayoutController.getFullShadeTransitionInset();
+ }
+ }
+
+ // Calculate the overshoot amount such that we're reaching the target after our desired
+ // distance, but only reach it fully once we drag a full shade length.
+ float transitionProgress = 0;
+ if (endPosition != 0 && progress != 0) {
+ transitionProgress = Interpolators.getOvershootInterpolation(progress,
+ mMaxOverscrollAmountForDragDown / endPosition,
+ (float) mDistanceForQSFullShadeTransition / (float) mView.getHeight());
+ }
+ mTransitioningToFullShadeProgress = transitionProgress;
+
+ int position = (int) MathUtils.lerp((float) 0, endPosition,
+ mTransitioningToFullShadeProgress);
+ if (mTransitioningToFullShadeProgress > 0.0f) {
+ // we want at least 1 pixel otherwise the panel won't be clipped
+ position = Math.max(1, position);
+ }
+ float overStretchAmount = Math.max(position - endPosition, 0.0f);
+ setOverStrechAmount(overStretchAmount);
+ mTransitionToFullShadeQSPosition = position;
+ updateQsExpansion();
+ }
+
private void trackMovement(MotionEvent event) {
if (mQsVelocityTracker != null) mQsVelocityTracker.addMovement(event);
}
@@ -2626,7 +2830,7 @@
if (!mKeyguardShowing) {
return;
}
- float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
+ float alphaQsExpansion = 1 - Math.min(1, computeQsExpansionFraction() * 2);
float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
* mKeyguardStatusBarAnimateAlpha;
newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount;
@@ -2649,7 +2853,7 @@
float expansionAlpha = MathUtils.map(
isUnlockHintRunning() ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f,
getExpandedFraction());
- float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
+ float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
mKeyguardBottomArea.setAffordanceAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(
@@ -2671,7 +2875,7 @@
float expansionAlpha = MathUtils.map(
isUnlockHintRunning() ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f,
getExpandedFraction());
- float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
+ float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
mBigClockContainer.setAlpha(alpha);
}
@@ -3223,6 +3427,7 @@
mHeightListener.onQsHeightChanged();
}
});
+ mLockscreenShadeTransitionController.setQS(mQs);
mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView());
updateQsExpansion();
}
@@ -3460,9 +3665,9 @@
StatusBar statusBar,
NotificationShelfController notificationShelfController) {
setStatusBar(statusBar);
- mNotificationStackScrollLayoutController.setNotificationPanelController(this);
mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
mNotificationShelfController = notificationShelfController;
+ mLockscreenShadeTransitionController.bindController(notificationShelfController);
updateMaxDisplayedNotifications(true);
}
@@ -3513,10 +3718,6 @@
return new OnLayoutChangeListener();
}
- public void setEmptyDragAmount(float amount) {
- mExpansionCallback.setEmptyDragAmount(amount);
- }
-
@Override
protected TouchHandler createTouchHandler() {
return new TouchHandler() {
@@ -3985,7 +4186,7 @@
mClockPositionResult.clockX,
mClockPositionResult.clockYFullyDozing,
mClockPositionResult.clockScale,
- false);
+ false /* animate */);
}
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
@@ -4001,11 +4202,7 @@
if (oldState == KEYGUARD && (goingToFullShade
|| statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
- long
- delay =
- mBarState == StatusBarState.SHADE_LOCKED ? 0
- : mKeyguardStateController.calculateGoingToFullShadeDelay();
- mQs.animateHeaderSlidingIn(delay);
+ updateQSMinHeight();
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
@@ -4052,11 +4249,12 @@
}
}
- private class ExpansionCallback implements PulseExpansionHandler.ExpansionCallback {
- public void setEmptyDragAmount(float amount) {
- mEmptyDragAmount = amount * 0.2f;
- positionClockAndNotifications();
- }
+ /**
+ * Sets the overstretch amount in raw pixels when dragging down.
+ */
+ public void setOverStrechAmount(float amount) {
+ mOverStretchAmount = amount;
+ positionClockAndNotifications(true /* forceUpdate */);
}
private class OnAttachStateChangeListener implements View.OnAttachStateChangeListener {
@@ -4103,11 +4301,7 @@
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
if (mQs != null) {
- float previousMin = mQsMinExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
- if (mQsExpansionHeight == previousMin) {
- mQsExpansionHeight = mQsMinExpansionHeight;
- }
+ updateQSMinHeight();
mQsMaxExpansionHeight = mQs.getDesiredHeight();
mNotificationStackScrollLayoutController.setMaxTopPadding(
mQsMaxExpansionHeight + mQsNotificationTopPadding);
@@ -4149,6 +4343,14 @@
}
}
+ private void updateQSMinHeight() {
+ float previousMin = mQsMinExpansionHeight;
+ mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+ if (mQsExpansionHeight == previousMin) {
+ mQsExpansionHeight = mQsMinExpansionHeight;
+ }
+ }
+
private class DebugDrawable extends Drawable {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 4d70237..7f4dabd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -34,15 +34,14 @@
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -73,7 +72,6 @@
private final DynamicPrivacyController mDynamicPrivacyController;
private final KeyguardBypassController mBypassController;
private final PluginManager mPluginManager;
- private final FalsingManager mFalsingManager;
private final FalsingCollector mFalsingCollector;
private final TunerService mTunerService;
private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@@ -87,6 +85,7 @@
private final ShadeController mShadeController;
private final NotificationShadeDepthController mDepthController;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private GestureDetector mGestureDetector;
@@ -119,7 +118,7 @@
PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController,
- FalsingManager falsingManager,
+ LockscreenShadeTransitionController transitionController,
FalsingCollector falsingCollector,
PluginManager pluginManager,
TunerService tunerService,
@@ -143,7 +142,7 @@
mPulseExpansionHandler = pulseExpansionHandler;
mDynamicPrivacyController = dynamicPrivacyController;
mBypassController = bypassController;
- mFalsingManager = falsingManager;
+ mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mPluginManager = pluginManager;
mTunerService = tunerService;
@@ -406,12 +405,7 @@
}
});
- ExpandHelper.Callback expandHelperCallback = mStackScrollLayout.getExpandHelperCallback();
- DragDownHelper.DragDownCallback dragDownCallback = mStackScrollLayout.getDragDownCallback();
- setDragDownHelper(
- new DragDownHelper(
- mView.getContext(), mView, expandHelperCallback,
- dragDownCallback, mFalsingManager, mFalsingCollector));
+ setDragDownHelper(mLockscreenShadeTransitionController.getTouchHelper());
mDepthController.setRoot(mView);
mNotificationPanelViewController.addExpansionListener(mDepthController);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c34fa2f..b94b5d3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -28,6 +28,7 @@
import android.os.Trace;
import android.util.Log;
import android.util.MathUtils;
+import android.util.Pair;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
@@ -42,10 +43,10 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
@@ -98,6 +99,18 @@
public static final int OPAQUE = 2;
private boolean mClipsQsScrim;
+ /**
+ * The amount of progress we are currently in if we're transitioning to the full shade.
+ * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
+ * shade.
+ */
+ private float mTransitionToFullShadeProgress;
+
+ /**
+ * If we're currently transitioning to the full shade.
+ */
+ private boolean mTransitioningToFullShade;
+
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
SEMI_TRANSPARENT,
@@ -357,7 +370,7 @@
+ mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
+ mNotificationsAlpha);
}
- applyExpansionToAlpha();
+ applyStateToAlpha();
// Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
// We need to disable focus otherwise AOD would end up with a gray overlay.
@@ -499,17 +512,47 @@
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
- applyAndDispatchExpansion();
+ applyAndDispatchState();
}
}
/**
+ * Set the amount of progress we are currently in if we're transitioning to the full shade.
+ * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
+ * shade.
+ */
+ public void setTransitionToFullShadeProgress(float progress) {
+ if (progress != mTransitionToFullShadeProgress) {
+ mTransitionToFullShadeProgress = progress;
+ setTransitionToFullShade(progress > 0.0f);
+ applyAndDispatchState();
+ }
+ }
+
+ /**
+ * Set if we're currently transitioning to the full shade
+ */
+ private void setTransitionToFullShade(boolean transitioning) {
+ if (transitioning != mTransitioningToFullShade) {
+ mTransitioningToFullShade = transitioning;
+ if (transitioning) {
+ // Let's make sure the shade locked is ready
+ ScrimState.SHADE_LOCKED.prepare(mState);
+ }
+ }
+ }
+
+
+ /**
* Set bounds for notifications background, all coordinates are absolute
*/
public void setNotificationsBounds(float left, float top, float right, float bottom) {
- mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
if (mClipsQsScrim) {
+ // "top - 1" to have 1 px of scrims overlap, see: b/186644628
+ mNotificationsScrim.setDrawableBounds(left, top - 1, right, bottom);
mScrimBehind.setBottomEdgePosition((int) top);
+ } else {
+ mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
}
}
@@ -534,7 +577,7 @@
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
- applyAndDispatchExpansion();
+ applyAndDispatchState();
}
}
@@ -553,6 +596,11 @@
if (mScrimBehind != null) {
mScrimBehind.enableBottomEdgeConcave(mClipsQsScrim);
}
+ if (mState != ScrimState.UNINITIALIZED) {
+ // the clipScrimState has changed, let's reprepare ourselves
+ mState.prepare(mState);
+ applyAndDispatchState();
+ }
}
@VisibleForTesting
@@ -583,7 +631,7 @@
}
}
- private void applyExpansionToAlpha() {
+ private void applyStateToAlpha() {
if (!mExpansionAffectsAlpha) {
return;
}
@@ -608,47 +656,40 @@
mInFrontAlpha = 0;
} else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.PULSING) {
- // Either darken of make the scrim transparent when you
- // pull down the shade
- float interpolatedFract = getInterpolatedFraction();
- float stateBehind = mClipsQsScrim ? mState.getNotifAlpha() : mState.getBehindAlpha();
- float backAlpha;
- if (mDarkenWhileDragging) {
- backAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
- interpolatedFract);
- } else {
- backAlpha = MathUtils.lerp(0 /* start */, stateBehind,
- interpolatedFract);
+ Pair<Integer, Float> result = calculateBackStateForState(mState);
+ int behindTint = result.first;
+ float behindAlpha = result.second;
+ if (mTransitionToFullShadeProgress > 0.0f) {
+ Pair<Integer, Float> shadeResult = calculateBackStateForState(
+ ScrimState.SHADE_LOCKED);
+ behindAlpha = MathUtils.lerp(behindAlpha, shadeResult.second,
+ mTransitionToFullShadeProgress);
+ behindTint = ColorUtils.blendARGB(behindTint, shadeResult.first,
+ mTransitionToFullShadeProgress);
}
mInFrontAlpha = mState.getFrontAlpha();
- int backTint;
if (mClipsQsScrim) {
- backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
- mState.getNotifTint(), interpolatedFract);
- } else {
- backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
- mState.getBehindTint(), interpolatedFract);
- }
- if (mQsExpansion > 0) {
- backAlpha = MathUtils.lerp(backAlpha, mDefaultScrimAlpha, mQsExpansion);
- int stateTint = mClipsQsScrim ? ScrimState.SHADE_LOCKED.getNotifTint()
- : ScrimState.SHADE_LOCKED.getBehindTint();
- backTint = ColorUtils.blendARGB(backTint, stateTint, mQsExpansion);
- }
- if (mClipsQsScrim) {
- mNotificationsAlpha = backAlpha;
- mNotificationsTint = backTint;
+ mNotificationsAlpha = behindAlpha;
+ mNotificationsTint = behindTint;
mBehindAlpha = 1;
mBehindTint = Color.BLACK;
} else {
- mBehindAlpha = backAlpha;
+ mBehindAlpha = behindAlpha;
if (mState == ScrimState.SHADE_LOCKED) {
// going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction();
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- mBehindTint = backTint;
+ if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ // Interpolate the notification alpha when transitioning!
+ mNotificationsAlpha = MathUtils.lerp(
+ mNotificationsAlpha,
+ getInterpolatedFraction(),
+ mTransitionToFullShadeProgress);
+ }
+ mNotificationsTint = mState.getNotifTint();
+ mBehindTint = behindTint;
}
}
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
@@ -658,8 +699,39 @@
}
}
- private void applyAndDispatchExpansion() {
- applyExpansionToAlpha();
+ private Pair<Integer, Float> calculateBackStateForState(ScrimState state) {
+ // Either darken of make the scrim transparent when you
+ // pull down the shade
+ float interpolatedFract = getInterpolatedFraction();
+ float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
+ float behindAlpha;
+ int behindTint;
+ if (mDarkenWhileDragging) {
+ behindAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
+ interpolatedFract);
+ } else {
+ behindAlpha = MathUtils.lerp(0 /* start */, stateBehind,
+ interpolatedFract);
+ }
+ if (mClipsQsScrim) {
+ behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
+ state.getNotifTint(), interpolatedFract);
+ } else {
+ behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
+ state.getBehindTint(), interpolatedFract);
+ }
+ if (mQsExpansion > 0) {
+ behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
+ int stateTint = mClipsQsScrim ? ScrimState.SHADE_LOCKED.getNotifTint()
+ : ScrimState.SHADE_LOCKED.getBehindTint();
+ behindTint = ColorUtils.blendARGB(behindTint, stateTint, mQsExpansion);
+ }
+ return new Pair<>(behindTint, behindAlpha);
+ }
+
+
+ private void applyAndDispatchState() {
+ applyStateToAlpha();
if (mUpdatePending) {
return;
}
@@ -1195,7 +1267,7 @@
public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
mExpansionAffectsAlpha = expansionAffectsAlpha;
if (expansionAffectsAlpha) {
- applyAndDispatchExpansion();
+ applyAndDispatchState();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index 2fa6795..2d41e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -14,8 +14,6 @@
package com.android.systemui.statusbar.phone;
-import android.view.View;
-
import com.android.systemui.statusbar.StatusBarState;
/**
@@ -78,15 +76,6 @@
void runPostCollapseRunnables();
/**
- * If secure with redaction: Show bouncer, go to unlocked shade.
- *
- * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
- *
- * @param startingChild The view to expand after going to the shade.
- */
- void goToLockedShade(View startingChild);
-
- /**
* Close the shade if it was open
*
* @return true if the shade was open, else false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
index a930a89..d4458e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.util.Log;
-import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
@@ -182,12 +181,6 @@
}
@Override
- public void goToLockedShade(View startingChild) {
- // TODO: Move this code out of StatusBar into ShadeController.
- getStatusBar().goToLockedShade(startingChild);
- }
-
- @Override
public boolean collapsePanel() {
if (!getNotificationPanelViewController().isFullyCollapsed()) {
// close the shade if it was open
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 ded3be43..9c6d623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -194,6 +194,7 @@
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LiftReveal;
import com.android.systemui.statusbar.LightRevealScrim;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -347,6 +348,8 @@
ONLY_CORE_APPS = onlyCoreApps;
}
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+
public interface ExpansionChangedListener {
void onExpansionChanged(float expansion, boolean expanded);
}
@@ -438,9 +441,6 @@
KeyguardIndicationController mKeyguardIndicationController;
- // RemoteInputView to be activated after unlock
- private View mPendingRemoteInputView;
-
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private View mReportRejectedTouch;
@@ -650,12 +650,6 @@
private final ScreenLifecycle mScreenLifecycle;
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final View.OnClickListener mGoToLockedShadeListener = v -> {
- if (mState == StatusBarState.KEYGUARD) {
- wakeUpIfDozing(SystemClock.uptimeMillis(), v, "SHADE_CLICK");
- goToLockedShade(null);
- }
- };
private boolean mNoAnimationOnNextBarModeChange;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -798,6 +792,7 @@
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
super(context);
@@ -882,6 +877,8 @@
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mFeatureFlags = featureFlags;
+ mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
+ lockscreenShadeTransitionController.setStatusbar(this);
mExpansionChangedListeners = new ArrayList<>();
@@ -1422,7 +1419,8 @@
mDozeScrimController, mScrimController, mNotificationShadeWindowController,
mDynamicPrivacyController, mKeyguardStateController,
mKeyguardIndicationController,
- this /* statusBar */, mShadeController, mCommandQueue, mInitController,
+ this /* statusBar */, mShadeController,
+ mLockscreenShadeTransitionController, mCommandQueue, mInitController,
mNotificationInterruptStateProvider);
mNotificationShelfController.setOnActivatedListener(mPresenter);
@@ -1502,7 +1500,6 @@
private void inflateShelf() {
mNotificationShelfController = mSuperStatusBarViewFactory
.getNotificationShelfController(mStackScroller);
- mNotificationShelfController.setOnClickListener(mGoToLockedShadeListener);
}
@Override
@@ -1675,7 +1672,7 @@
final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
|| !mUserSwitcherController.isSimpleUserSwitcher())
- && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
+ && !isShadeDisabled()
&& ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
&& !mDozing
&& !ONLY_CORE_APPS;
@@ -1683,6 +1680,10 @@
Log.d(TAG, "updateQsExpansionEnabled - QS Expand enabled: " + expandEnabled);
}
+ public boolean isShadeDisabled() {
+ return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
+ }
+
public void addQsTile(ComponentName tile) {
if (mQSPanelController != null && mQSPanelController.getHost() != null) {
mQSPanelController.getHost().addTile(tile);
@@ -3333,7 +3334,6 @@
public void showKeyguard() {
mStatusBarStateController.setKeyguardRequested(true);
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
- mPendingRemoteInputView = null;
updateIsKeyguard();
mAssistManagerLazy.get().onLockscreenShown();
}
@@ -3392,11 +3392,6 @@
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
updatePanelExpansionForKeyguard();
- if (mDraggedDownEntry != null) {
- mDraggedDownEntry.setUserLocked(false);
- mDraggedDownEntry.notifyHeightChanged(false /* needsAnimation */);
- mDraggedDownEntry = null;
- }
}
private void updatePanelExpansionForKeyguard() {
@@ -3524,11 +3519,7 @@
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
}
long delay = mKeyguardStateController.calculateGoingToFullShadeDelay();
- mNotificationPanelViewController.animateToFullShade(delay);
- if (mDraggedDownEntry != null) {
- mDraggedDownEntry.setUserLocked(false);
- mDraggedDownEntry = null;
- }
+ mLockscreenShadeTransitionController.onHideKeyguard(delay);
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3715,7 +3706,23 @@
private void showBouncerIfKeyguard() {
if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
&& !mKeyguardViewMediator.isHiding()) {
- mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
+ }
+ }
+
+ /**
+ * Show the bouncer if we're currently on the keyguard or shade locked and aren't hiding.
+ * @param performAction the action to perform when the bouncer is dismissed.
+ * @param cancelAction the action to perform when unlock is aborted.
+ */
+ public void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
+ Runnable cancelAction) {
+ if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
+ && !mKeyguardViewMediator.isHiding()) {
+ mStatusBarKeyguardViewManager.dismissWithAction(performAction, cancelAction,
+ false /* afterKeyguardGone */);
+ } else if (cancelAction != null) {
+ cancelAction.run();
}
}
@@ -3896,47 +3903,6 @@
}
/**
- * If secure with redaction: Show bouncer, go to unlocked shade.
- *
- * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
- *
- * @param expandView The view to expand after going to the shade.
- */
- void goToLockedShade(View expandView) {
- if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- return;
- }
-
- int userId = mLockscreenUserManager.getCurrentUserId();
- ExpandableNotificationRow row = null;
- NotificationEntry entry = null;
- if (expandView instanceof ExpandableNotificationRow) {
- entry = ((ExpandableNotificationRow) expandView).getEntry();
- entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
- // Indicate that the group expansion is changing at this time -- this way the group
- // and children backgrounds / divider animations will look correct.
- entry.setGroupExpansionChanging(true);
- userId = entry.getSbn().getUserId();
- }
- boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
- userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
- || !mLockscreenUserManager.shouldShowLockscreenNotifications()
- || mFalsingCollector.shouldEnforceBouncer();
- if (mKeyguardBypassController.getBypassEnabled()) {
- fullShadeNeedsBouncer = false;
- }
- if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
- showBouncerIfKeyguard();
- mDraggedDownEntry = entry;
- mPendingRemoteInputView = null;
- } else {
- mNotificationPanelViewController.animateToFullShade(0 /* delay */);
- mStatusBarStateController.setState(StatusBarState.SHADE_LOCKED);
- }
- }
-
- /**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
public void setBouncerShowing(boolean bouncerShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 41bd710..91d1bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -365,6 +365,26 @@
return false;
}
+ /**
+ * If applicable, shows the alternate authentication bouncer. Else, shows the input
+ * (pin/password/pattern) bouncer.
+ * @param scrimmed true when the input bouncer should show scrimmed, false when the user will be
+ * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
+ */
+ public void showGenericBouncer(boolean scrimmed) {
+ if (mAlternateAuthInterceptor != null) {
+ if (mAlternateAuthInterceptor.showAlternateAuthBouncer()) {
+ mStatusBar.updateScrimController();
+ }
+ return;
+ }
+
+ showBouncer(scrimmed);
+ }
+
+ /**
+ * Hides the input bouncer (pin/password/pattern).
+ */
@VisibleForTesting
void hideBouncer(boolean destroyView) {
if (mBouncer == null) {
@@ -380,7 +400,7 @@
}
/**
- * Shows the keyguard bouncer - the password challenge on the lock screen
+ * Shows the keyguard input bouncer - the password challenge on the lock screen
*
* @param scrimmed true when the bouncer should show scrimmed, false when the user will be
* dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 75c544d..aa58527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -48,6 +48,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -112,6 +113,7 @@
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
private final ShadeController mShadeController;
+ private final LockscreenShadeTransitionController mShadeTransitionController;
private final CommandQueue mCommandQueue;
private final AccessibilityManager mAccessibilityManager;
@@ -138,6 +140,7 @@
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
ShadeController shadeController,
+ LockscreenShadeTransitionController shadeTransitionController,
CommandQueue commandQueue,
InitController initController,
NotificationInterruptStateProvider notificationInterruptStateProvider) {
@@ -149,6 +152,7 @@
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
mShadeController = shadeController;
+ mShadeTransitionController = shadeTransitionController;
mCommandQueue = commandQueue;
mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -394,7 +398,7 @@
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
- mShadeController.goToLockedShade(clickedEntry.getRow());
+ mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
} else if (clickedEntry.isSensitive()
&& mDynamicPrivacyController.isInLockedDownShade()) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 8465889..779ba1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.systemBars;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
@@ -32,7 +29,6 @@
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Gravity;
-import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
@@ -53,8 +49,6 @@
private int mRightInset = 0;
private int mTopInset = 0;
- private float mTouchDownY = 0;
-
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -73,28 +67,6 @@
return windowInsets;
}
- /**
- * This is specifically for pulling down the status bar as a consistent motion in the visual
- * immersive mode. In the visual immersive mode, after the system detects a system gesture
- * motion from the top, we show permanent bars, and then forward the touch events from the
- * focused window to the status bar window. However, since the first relayed event is out of
- * bound of the status bar view, in order for the touch event to be correctly dispatched down,
- * we jot down the position Y of the initial touch down event, offset it to 0 in the y-axis,
- * and calculate the movement based on first touch down position.
- */
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (ev.getAction() == ACTION_DOWN && ev.getRawY() > getHeight()) {
- mTouchDownY = ev.getRawY();
- ev.setLocation(ev.getRawX(), mTopInset);
- } else if (ev.getAction() == ACTION_MOVE && mTouchDownY != 0) {
- ev.setLocation(ev.getRawX(), mTopInset + ev.getRawY() - mTouchDownY);
- } else if (ev.getAction() == ACTION_UP) {
- mTouchDownY = 0;
- }
- return super.dispatchTouchEvent(ev);
- }
-
private void applyMargins() {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index d0d2cb2..9722d68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -213,6 +214,7 @@
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
return new StatusBar(
@@ -299,6 +301,7 @@
ongoingCallController,
animationScheduler,
locationPublisher,
+ transitionController,
featureFlags,
keyguardUnlockAnimationController);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index e9d256c..a019895 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -23,7 +23,7 @@
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
import android.content.Intent
import android.util.Log
-import android.view.ViewGroup
+import android.view.View
import android.widget.Chronometer
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
@@ -57,7 +57,7 @@
private var ongoingCallInfo: OngoingCallInfo? = null
/** True if the application managing the call is visible to the user. */
private var isCallAppVisible: Boolean = true
- private var chipView: ViewGroup? = null
+ private var chipView: View? = null
private var uidObserver: IUidObserver.Stub? = null
private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
@@ -82,16 +82,14 @@
entry.sbn.notification.contentIntent.intent,
entry.sbn.uid)
updateChip()
+ } else if (isCallNotification(entry)) {
+ removeChip()
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
if (isOngoingCallNotification(entry)) {
- ongoingCallInfo = null
- mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
- if (uidObserver != null) {
- iActivityManager.unregisterUidObserver(uidObserver)
- }
+ removeChip()
}
}
}
@@ -107,7 +105,7 @@
*
* Should only be called from [CollapsedStatusBarFragment].
*/
- fun setChipView(chipView: ViewGroup) {
+ fun setChipView(chipView: View) {
this.chipView = chipView
if (hasOngoingCall()) {
updateChip()
@@ -224,6 +222,14 @@
return procState <= ActivityManager.PROCESS_STATE_TOP
}
+ private fun removeChip() {
+ ongoingCallInfo = null
+ mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
+ if (uidObserver != null) {
+ iActivityManager.unregisterUidObserver(uidObserver)
+ }
+ }
+
private class OngoingCallInfo(
val callStartTime: Long,
val intent: Intent,
@@ -233,10 +239,15 @@
private fun isOngoingCallNotification(entry: NotificationEntry): Boolean {
val extras = entry.sbn.notification.extras
- val callStyleTemplateName = Notification.CallStyle::class.java.name
- return extras.getString(Notification.EXTRA_TEMPLATE) == callStyleTemplateName &&
+ return isCallNotification(entry) &&
extras.getInt(Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING
}
+private fun isCallNotification(entry: NotificationEntry): Boolean {
+ val extras = entry.sbn.notification.extras
+ val callStyleTemplateName = Notification.CallStyle::class.java.name
+ return extras.getString(Notification.EXTRA_TEMPLATE) == callStyleTemplateName
+}
+
private const val TAG = "OngoingCallController"
private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 4cba432..83aa01f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -16,6 +16,9 @@
package com.android.systemui.wallet.ui;
+import static android.provider.Settings.ACTION_LOCKSCREEN_SETTINGS;
+
+import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -178,7 +181,10 @@
finish();
return true;
} else if (itemId == R.id.wallet_lockscreen_settings) {
- // TODO(b/186496392): Navigate to Lock Screen Settings page when the item is clicked.
+ Intent intent =
+ new Intent(ACTION_LOCKSCREEN_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mActivityStarter.startActivity(intent, true);
return true;
}
return super.onOptionsItemSelected(item);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 98467d4..10322f2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -232,6 +232,13 @@
verify(mView).removeView(mFakeSmartspaceView);
}
+ @Test
+ public void testRefresh() {
+ mController.refresh();
+
+ verify(mSmartspaceController).requestSmartspaceUpdate();
+ }
+
private void verifyAttachment(VerificationMode times) {
verify(mClockManager, times).addOnClockChangedListener(
any(ClockManager.ClockChangedListener.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
index 42314bf..6f2c565 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
@@ -81,7 +81,7 @@
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, false);
mTestableResources.addOverride(
- com.android.internal.R.bool.config_enableOneHandedKeyguard, false);
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning, false);
when(mKeyguardSecurityContainerControllerFactory.create(any(
KeyguardSecurityContainer.SecurityCallback.class)))
@@ -150,7 +150,7 @@
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, false);
mTestableResources.addOverride(
- com.android.internal.R.bool.config_enableOneHandedKeyguard, false);
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning, false);
mKeyguardHostViewController.init();
assertEquals(
@@ -161,7 +161,7 @@
mTestableResources.addOverride(
R.bool.can_use_one_handed_bouncer, true);
mTestableResources.addOverride(
- com.android.internal.R.bool.config_enableOneHandedKeyguard, true);
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning, true);
mKeyguardHostViewController.updateResources();
assertEquals(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 9557d5c..f5916e7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -246,7 +246,8 @@
boolean sysuiResourceCanUseOneHandedKeyguard,
SecurityMode securityMode) {
TestableResources testableResources = mContext.getOrCreateTestableResources();
- testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard,
+ testableResources.addOverride(
+ com.android.internal.R.bool.config_enableDynamicKeyguardPositioning,
deviceConfigCanUseOneHandedKeyguard);
testableResources.addOverride(R.bool.can_use_one_handed_bouncer,
sysuiResourceCanUseOneHandedKeyguard);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index f779305..29b4405 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -943,6 +943,34 @@
}
@Test
+ public void testShouldNotUpdateBiometricListeningStateOnStatusBarStateChange() {
+ // GIVEN state for face auth should run aside from StatusBarState
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(null,
+ KeyguardUpdateMonitor.getCurrentUser())).thenReturn(0);
+ mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
+ setKeyguardBouncerVisibility(false /* isVisible */);
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+ when(mKeyguardBypassController.canBypass()).thenReturn(true);
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+
+ // WHEN status bar state reports a change to the keyguard that would normally indicate to
+ // start running face auth
+ mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isEqualTo(true);
+
+ // THEN face unlock is not running b/c status bar state changes don't cause biometric
+ // listening state to update
+ assertThat(mKeyguardUpdateMonitor.isFaceUnlockRunning(
+ KeyguardUpdateMonitor.getCurrentUser())).isEqualTo(false);
+
+ // WHEN biometric listening state is updated
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+
+ // THEN face unlock is running
+ assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(true);
+ }
+
+ @Test
public void testRequireUnlockForNfc_Broadcast() {
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(callback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index a974421..c6aef4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import org.junit.Assert.assertNotNull
@@ -79,6 +80,8 @@
private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock
private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock
+ private lateinit var configurationController: ConfigurationController
@Captor
private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
@Captor
@@ -98,6 +101,7 @@
bypassController,
mediaCarouselController,
notificationLockscreenUserManager,
+ configurationController,
wakefulnessLifecycle,
statusBarKeyguardViewManager)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index ba2b37c..75cf855 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -20,7 +20,9 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -75,6 +77,7 @@
mQsPanelController = mock(QSPanelController.class);
mQuickHeader = mock(QuickStatusBarHeader.class);
mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class));
+ mQsDetail.mClipper = mock(QSDetailClipper.class);
mMockDetailAdapter = mock(DetailAdapter.class);
when(mMockDetailAdapter.createDetailView(any(), any(), any()))
@@ -115,6 +118,62 @@
}
@Test
+ public void testShowDetail_ShouldAnimate() {
+ mTestableLooper.processAllMessages();
+
+ when(mMockDetailAdapter.shouldAnimate()).thenReturn(true);
+ mQsDetail.setFullyExpanded(true);
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
+ eq(true) /* in */, any());
+ clearInvocations(mQsDetail.mClipper);
+
+ mQsDetail.handleShowingDetail(null, 0, 0, false);
+ verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
+ eq(false) /* in */, any());
+ }
+
+ @Test
+ public void testShowDetail_ShouldNotAnimate() {
+ mTestableLooper.processAllMessages();
+
+ when(mMockDetailAdapter.shouldAnimate()).thenReturn(false);
+ mQsDetail.setFullyExpanded(true);
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ verify(mQsDetail.mClipper).updateCircularClip(eq(false) /* animate */, anyInt(), anyInt(),
+ eq(true) /* in */, any());
+ clearInvocations(mQsDetail.mClipper);
+
+ mQsDetail.handleShowingDetail(null, 0, 0, false);
+ verify(mQsDetail.mClipper).updateCircularClip(eq(false) /* animate */, anyInt(), anyInt(),
+ eq(false) /* in */, any());
+ }
+
+ @Test
+ public void testDoneButton_CloseDetailPanel() {
+ mTestableLooper.processAllMessages();
+
+ when(mMockDetailAdapter.onDoneButtonClicked()).thenReturn(false);
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ mQsDetail.requireViewById(android.R.id.button1).performClick();
+ verify(mQsPanelController).closeDetail();
+ }
+
+ @Test
+ public void testDoneButton_KeepDetailPanelOpen() {
+ mTestableLooper.processAllMessages();
+
+ when(mMockDetailAdapter.onDoneButtonClicked()).thenReturn(true);
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ mQsDetail.requireViewById(android.R.id.button1).performClick();
+ verify(mQsPanelController, never()).closeDetail();
+ }
+
+ @Test
public void testMoreSettingsButton() {
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
new file mode 100644
index 0000000..18b6c30
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -0,0 +1,225 @@
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.util.DisplayMetrics
+import androidx.test.filters.SmallTest
+import com.android.systemui.ExpandHelper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.media.MediaHierarchyManager
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger
+import com.android.systemui.statusbar.phone.NotificationPanelViewController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.StatusBar
+import com.android.systemui.statusbar.policy.ConfigurationController
+import org.junit.After
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
+
+private fun <T> anyObject(): T {
+ return Mockito.anyObject<T>()
+}
+
+@SmallTest
+@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner::class)
+class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
+
+ lateinit var transitionController: LockscreenShadeTransitionController
+ lateinit var row: ExpandableNotificationRow
+ @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
+ @Mock lateinit var lockscreenGestureLogger: LockscreenGestureLogger
+ @Mock lateinit var keyguardBypassController: KeyguardBypassController
+ @Mock lateinit var lockScreenUserManager: NotificationLockscreenUserManager
+ @Mock lateinit var falsingCollector: FalsingCollector
+ @Mock lateinit var ambientState: AmbientState
+ @Mock lateinit var displayMetrics: DisplayMetrics
+ @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
+ @Mock lateinit var scrimController: ScrimController
+ @Mock lateinit var configurationController: ConfigurationController
+ @Mock lateinit var falsingManager: FalsingManager
+ @Mock lateinit var notificationPanelController: NotificationPanelViewController
+ @Mock lateinit var nsslController: NotificationStackScrollLayoutController
+ @Mock lateinit var featureFlags: FeatureFlags
+ @Mock lateinit var stackscroller: NotificationStackScrollLayout
+ @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
+ @Mock lateinit var statusbar: StatusBar
+ @Mock lateinit var qS: QS
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
+ @Before
+ fun setup() {
+ val helper = NotificationTestHelper(
+ mContext,
+ mDependency,
+ TestableLooper.get(this))
+ row = helper.createRow()
+ transitionController = LockscreenShadeTransitionController(
+ statusBarStateController = statusbarStateController,
+ lockscreenGestureLogger = lockscreenGestureLogger,
+ keyguardBypassController = keyguardBypassController,
+ lockScreenUserManager = lockScreenUserManager,
+ falsingCollector = falsingCollector,
+ ambientState = ambientState,
+ displayMetrics = displayMetrics,
+ mediaHierarchyManager = mediaHierarchyManager,
+ scrimController = scrimController,
+ featureFlags = featureFlags,
+ context = context,
+ configurationController = configurationController,
+ falsingManager = falsingManager
+ )
+ whenever(nsslController.view).thenReturn(stackscroller)
+ whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
+ transitionController.notificationPanelController = notificationPanelController
+ transitionController.statusbar = statusbar
+ transitionController.qS = qS
+ transitionController.setStackScroller(nsslController)
+ whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(nsslController.isInLockedDownShade).thenReturn(false)
+ whenever(qS.isFullyCollapsed).thenReturn(true)
+ whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
+ true)
+ whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
+ whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
+ whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
+ whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
+ clearInvocations(statusbar)
+ }
+
+ @After
+ fun tearDown() {
+ transitionController.dragDownAnimator?.cancel()
+ }
+
+ @Test
+ fun testCantDragDownWhenQSExpanded() {
+ assertTrue("Can't drag down on keyguard", transitionController.canDragDown())
+ whenever(qS.isFullyCollapsed).thenReturn(false)
+ assertFalse("Can drag down when QS is expanded", transitionController.canDragDown())
+ }
+
+ @Test
+ fun testCanDragDownInLockedDownShade() {
+ whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ assertFalse("Can drag down in shade locked", transitionController.canDragDown())
+ whenever(nsslController.isInLockedDownShade).thenReturn(true)
+ assertTrue("Can't drag down in locked down shade", transitionController.canDragDown())
+ }
+
+ @Test
+ fun testGoingToLockedShade() {
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
+ }
+
+ @Test
+ fun testGoToLockedShadeOnlyOnKeyguard() {
+ whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ transitionController.goToLockedShade(null)
+ whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE)
+ transitionController.goToLockedShade(null)
+ whenever(statusbarStateController.state).thenReturn(StatusBarState.FULLSCREEN_USER_SWITCHER)
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController, never()).setState(anyInt())
+ }
+
+ @Test
+ fun testDontGoWhenShadeDisabled() {
+ whenever(statusbar.isShadeDisabled).thenReturn(true)
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController, never()).setState(anyInt())
+ }
+
+ @Test
+ fun testUserExpandsViewOnGoingToFullShade() {
+ assertFalse("Row shouldn't be user expanded yet", row.isUserExpanded)
+ transitionController.goToLockedShade(row)
+ assertTrue("Row wasn't user expanded on drag down", row.isUserExpanded)
+ }
+
+ @Test
+ fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() {
+ whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
+ false)
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController, never()).setState(anyInt())
+ verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
+ verify(statusbar).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
+ }
+
+ @Test
+ fun testTriggeringBouncerNoNotificationsOnLockscreen() {
+ whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController, never()).setState(anyInt())
+ verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
+ verify(statusbar).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
+ }
+
+ @Test
+ fun testGoToLockedShadeCreatesQSAnimation() {
+ transitionController.goToLockedShade(null)
+ verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
+ verify(notificationPanelController).animateToFullShade(anyLong())
+ assertNotNull(transitionController.dragDownAnimator)
+ }
+
+ @Test
+ fun testGoToLockedShadeDoesntCreateQSAnimation() {
+ transitionController.goToLockedShade(null, needsQSAnimation = false)
+ verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
+ verify(notificationPanelController).animateToFullShade(anyLong())
+ assertNull(transitionController.dragDownAnimator)
+ }
+
+ @Test
+ fun testDragDownAmountDoesntCallOutInLockedDownShade() {
+ whenever(nsslController.isInLockedDownShade).thenReturn(true)
+ transitionController.dragDownAmount = 10f
+ verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat())
+ verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
+ verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+ verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
+ anyBoolean(), anyLong())
+ verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ }
+
+ @Test
+ fun testDragDownAmountCallsOut() {
+ transitionController.dragDownAmount = 10f
+ verify(nsslController).setTransitionToFullShadeAmount(anyFloat())
+ verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
+ verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+ verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
+ anyBoolean(), anyLong())
+ verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 84fb368..8758e16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -142,7 +142,6 @@
mNotificationSectionsManager,
mGroupMembershipManger,
mGroupExpansionManager,
- mStatusBarStateController,
mAmbientState,
mFeatureFlags);
mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 895339f..f376e88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -50,6 +50,7 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -121,6 +122,7 @@
@Mock private NotificationEntryManager mEntryManager;
@Mock private IStatusBarService mIStatusBarService;
@Mock private UiEventLogger mUiEventLogger;
+ @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private ForegroundServiceDismissalFeatureController mFgFeatureController;
@Mock private ForegroundServiceSectionController mFgServicesSectionController;
@Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView;
@@ -173,6 +175,7 @@
mNotifPipeline,
mNotifCollection,
mEntryManager,
+ mLockscreenShadeTransitionController,
mIStatusBarService,
mUiEventLogger,
mFgFeatureController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 45761df..6b4797f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -82,6 +82,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -102,6 +103,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -225,6 +227,8 @@
@Mock
private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock
private AuthController mAuthController;
@Mock
private ScrimController mScrimController;
@@ -246,6 +250,8 @@
private KeyguardMediaController mKeyguardMediaController;
@Mock
private PrivacyDotViewController mPrivacyDotViewController;
+ @Mock
+ private SecureSettings mSecureSettings;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -311,7 +317,9 @@
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
- new FalsingManagerFake(), new FalsingCollectorFake());
+ new FalsingManagerFake(),
+ mLockscreenShadeTransitionController,
+ new FalsingCollectorFake());
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -327,7 +335,7 @@
mResources,
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
- new FalsingManagerFake(), new FalsingCollectorFake(), mShadeController,
+ new FalsingManagerFake(), new FalsingCollectorFake(),
mNotificationLockscreenUserManager, mNotificationEntryManager,
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
@@ -341,6 +349,7 @@
mKeyguardQsUserSwitchComponentFactory,
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
+ mLockscreenShadeTransitionController,
mQSDetailDisplayer,
mGroupManager,
mNotificationAreaController,
@@ -355,7 +364,8 @@
mQuickAccessWalletClient,
mKeyguardMediaController,
mPrivacyDotViewController,
- new FakeExecutor(new FakeSystemClock()));
+ new FakeExecutor(new FakeSystemClock()),
+ mSecureSettings);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 0a3eec4d..6c1a3c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -31,12 +31,12 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
-import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -89,6 +89,7 @@
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Before
public void setUp() {
@@ -112,7 +113,7 @@
mPulseExpansionHandler,
mDynamicPrivacyController,
mBypassController,
- new FalsingManagerFake(),
+ mLockscreenShadeTransitionController,
new FalsingCollectorFake(),
mPluginManager,
mTunerService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index f98f00c..a431a78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -41,6 +41,7 @@
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.MathUtils;
import android.view.View;
import androidx.test.filters.SmallTest;
@@ -1121,6 +1122,32 @@
assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.8f, /* expansion */ 0.2f);
}
+ @Test
+ public void testNotificationTransparency_followsTransitionToFullShade() {
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setPanelExpansion(1.0f);
+ finishAnimationsImmediately();
+ float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setPanelExpansion(1.0f);
+ finishAnimationsImmediately();
+ float keyguardAlpha = mNotificationsScrim.getViewAlpha();
+
+ mScrimController.setClipsQsScrim(true);
+ float progress = 0.5f;
+ mScrimController.setTransitionToFullShadeProgress(progress);
+ assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
+ mNotificationsScrim.getViewAlpha(), 0.2);
+ progress = 0.0f;
+ mScrimController.setTransitionToFullShadeProgress(progress);
+ assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
+ mNotificationsScrim.getViewAlpha(), 0.2);
+ progress = 1.0f;
+ mScrimController.setTransitionToFullShadeProgress(progress);
+ assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
+ mNotificationsScrim.getViewAlpha(), 0.2);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setPanelExpansion(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 8601de5..ce45f26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -40,6 +40,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -127,7 +128,8 @@
mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class),
mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class), mStatusBar,
- mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
+ mock(ShadeControllerImpl.class), mock(LockscreenShadeTransitionController.class),
+ mCommandQueue, mInitController,
mNotificationInterruptStateProvider);
mInitController.executePostInitTasks();
ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index b3d52b8..5a3683e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -101,6 +101,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -267,6 +268,7 @@
@Mock private OngoingCallController mOngoingCallController;
@Mock private SystemStatusAnimationScheduler mAnimationScheduler;
@Mock private StatusBarLocationPublisher mLocationPublisher;
+ @Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private IWallpaperManager mWallpaperManager;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -437,6 +439,7 @@
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
+ mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController);
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
index 0e77bb3..e32af60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
@@ -20,7 +20,6 @@
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
-import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -48,8 +47,7 @@
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- val chipView = LayoutInflater.from(mContext)
- .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ val chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
textView = chipView.findViewById(R.id.ongoing_call_chip_time)!!
measureTextView()
calculateDoesNotFixText()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 9a7ab28..3a71ecf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -27,6 +27,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
+import android.view.View
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
@@ -80,14 +81,13 @@
@Mock private lateinit var mockActivityStarter: ActivityStarter
@Mock private lateinit var mockIActivityManager: IActivityManager
- private lateinit var chipView: LinearLayout
+ private lateinit var chipView: View
@Before
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- chipView = LayoutInflater.from(mContext)
- .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
}
MockitoAnnotations.initMocks(this)
@@ -116,7 +116,7 @@
}
@Test
- fun onEntryUpdated_isOngoingCallNotif_listenerNotifiedWithRightCallTime() {
+ fun onEntryUpdated_isOngoingCallNotif_listenerNotified() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
@@ -130,6 +130,15 @@
}
@Test
+ fun onEntryUpdated_ongoingCallNotifThenScreeningCallNotif_listenerNotifiedTwice() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ notifCollectionListener.onEntryUpdated(createScreeningCallNotifEntry())
+
+ verify(mockOngoingCallListener, times(2))
+ .onOngoingCallStateChanged(anyBoolean())
+ }
+
+ @Test
fun onEntryRemoved_ongoingCallNotif_listenerNotified() {
notifCollectionListener.onEntryRemoved(createOngoingCallNotifEntry(), REASON_USER_STOPPED)
@@ -188,6 +197,22 @@
assertThat(controller.hasOngoingCall()).isFalse()
}
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentThenScreeningCallNotifSent_returnsFalse() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ notifCollectionListener.onEntryUpdated(createScreeningCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall()).isFalse()
+ }
+
+ @Test
+ fun hasOngoingCall_ongoingCallNotifSentThenUnrelatedNotifSent_returnsTrue() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ notifCollectionListener.onEntryUpdated(createNotCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall()).isTrue()
+ }
+
/**
* This test fakes a theme change during an ongoing call.
*
@@ -200,10 +225,9 @@
// Start an ongoing call.
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- lateinit var newChipView: LinearLayout
+ lateinit var newChipView: View
TestableLooper.get(this).runWithLooper {
- newChipView = LayoutInflater.from(mContext)
- .inflate(R.layout.ongoing_call_chip, null) as LinearLayout
+ newChipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_call_chip, null)
}
// Change the chip view associated with the controller.
@@ -281,9 +305,13 @@
// Other tests for notifyChipVisibilityChanged are in [OngoingCallLogger], since
// [OngoingCallController.notifyChipVisibilityChanged] just delegates to that class.
- private fun createOngoingCallNotifEntry(): NotificationEntry {
+ private fun createOngoingCallNotifEntry() = createCallNotifEntry(ongoingCallStyle)
+
+ private fun createScreeningCallNotifEntry() = createCallNotifEntry(screeningCallStyle)
+
+ private fun createCallNotifEntry(callStyle: Notification.CallStyle): NotificationEntry {
val notificationEntryBuilder = NotificationEntryBuilder()
- notificationEntryBuilder.modifyNotification(context).style = ongoingCallStyle
+ notificationEntryBuilder.modifyNotification(context).style = callStyle
val contentIntent = mock(PendingIntent::class.java)
`when`(contentIntent.intent).thenReturn(mock(Intent::class.java))
@@ -295,6 +323,9 @@
private fun createNotCallNotifEntry() = NotificationEntryBuilder().build()
}
-private val ongoingCallStyle = Notification.CallStyle.forOngoingCall(
- Person.Builder().setName("name").build(),
- /* hangUpIntent= */ mock(PendingIntent::class.java))
+private val person = Person.Builder().setName("name").build()
+private val hangUpIntent = mock(PendingIntent::class.java)
+
+private val ongoingCallStyle = Notification.CallStyle.forOngoingCall(person, hangUpIntent)
+private val screeningCallStyle = Notification.CallStyle.forScreeningCall(
+ person, hangUpIntent, /* answerIntent= */ mock(PendingIntent::class.java))
\ No newline at end of file
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 3bb6e08..85084f4 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1839,8 +1839,6 @@
// For a full update we replace the RemoteViews completely.
widget.views = views;
}
- widget.views.setProviderInstanceId(UPDATE_COUNTER.get());
-
int memoryUsage;
if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
(widget.views != null) &&
@@ -1942,13 +1940,14 @@
return;
}
if (updateViews != null) {
+ updateViews = new RemoteViews(updateViews);
updateViews.setProviderInstanceId(requestId);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = widget.host;
args.arg2 = widget.host.callbacks;
- args.arg3 = (updateViews != null) ? updateViews.clone() : null;
+ args.arg3 = updateViews;
args.arg4 = requestId;
args.argi1 = widget.appWidgetId;
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index ca59ce3..baec544 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -1320,12 +1320,12 @@
private void setUserRestriction(int userId, int sensor, boolean enabled) {
if (sensor == CAMERA) {
mAppOpsManager.setUserRestrictionForUser(OP_CAMERA, enabled,
- mAppOpsRestrictionToken, new String[]{}, userId);
+ mAppOpsRestrictionToken, null, userId);
} else if (sensor == MICROPHONE) {
mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO, enabled,
- mAppOpsRestrictionToken, new String[]{}, userId);
+ mAppOpsRestrictionToken, null, userId);
mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO_HOTWORD, enabled,
- mAppOpsRestrictionToken, new String[]{}, userId);
+ mAppOpsRestrictionToken, null, userId);
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a1a4418..0c785da 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1850,7 +1850,7 @@
public StorageManagerService(Context context) {
sSelf = this;
mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
- ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mContext = context;
mResolver = mContext.getContentResolver();
mCallbacks = new Callbacks(FgThread.get().getLooper());
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 7a0a3a7..670f557 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -699,7 +699,7 @@
if (mActivity != null) {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null, null,
- localSubject, report.toString(), stack, null, null, null);
+ localSubject, report.toString(), stack, null, null, null, null);
}
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED,
localSubject);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f480cbc..aadb25c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,8 +16,6 @@
package com.android.server.am;
-import static android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND;
-import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
@@ -5833,26 +5831,6 @@
}
}
- // Check for CDM apps with either REQUEST_COMPANION_RUN_IN_BACKGROUND or
- // REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND.
- // Note: When a CDM app has REQUEST_COMPANION_RUN_IN_BACKGROUND, the app is also put
- // in the user-allowlist. However, in this case, we want to use the reason code
- // REASON_COMPANION_DEVICE_MANAGER, so this check needs to be before the
- // isAllowlistedForFgsStartLOSP check.
- if (ret == REASON_DENIED) {
- final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
- UserHandle.getUserId(callingUid), callingUid);
- if (isCompanionApp) {
- if (isPermissionGranted(
- REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND,
- callingPid, callingUid)
- || isPermissionGranted(REQUEST_COMPANION_RUN_IN_BACKGROUND,
- callingPid, callingUid)) {
- ret = REASON_COMPANION_DEVICE_MANAGER;
- }
- }
- }
-
if (ret == REASON_DENIED) {
ActivityManagerService.FgsTempAllowListItem item =
mAm.isAllowlistedForFgsStartLOSP(callingUid);
@@ -5880,6 +5858,14 @@
}
if (ret == REASON_DENIED) {
+ final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
+ UserHandle.getUserId(callingUid), callingUid);
+ if (isCompanionApp) {
+ ret = REASON_COMPANION_DEVICE_MANAGER;
+ }
+ }
+
+ if (ret == REASON_DENIED) {
final AppOpsManager appOpsManager = mAm.getAppOpsManager();
if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, callingUid,
callingPackage) == AppOpsManager.MODE_ALLOWED) {
@@ -5898,10 +5884,6 @@
return ret;
}
- private boolean isPermissionGranted(String permission, int callingPid, int callingUid) {
- return mAm.checkPermission(permission, callingPid, callingUid) == PERMISSION_GRANTED;
- }
-
private static boolean isFgsBgStart(@ReasonCode int code) {
return code != REASON_PROC_STATE_PERSISTENT
&& code != REASON_PROC_STATE_PERSISTENT_UI
@@ -5975,7 +5957,7 @@
}
FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid,
- null,
+ r.shortInstanceName,
state,
r.mAllowWhileInUsePermissionInFgs,
r.mAllowStartForeground,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6661f88..d3955eb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -351,6 +351,7 @@
import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
import com.android.server.DeviceIdleInternal;
@@ -420,6 +421,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
@@ -621,6 +623,8 @@
@GuardedBy("this")
BroadcastStats mCurBroadcastStats;
+ TraceErrorLogger mTraceErrorLogger;
+
BroadcastQueue broadcastQueueForIntent(Intent intent) {
if (isOnOffloadQueue(intent.getFlags())) {
if (DEBUG_BROADCAST_BACKGROUND) {
@@ -2336,6 +2340,7 @@
mInternal = new LocalService();
mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mTraceErrorLogger = new TraceErrorLogger();
}
public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -7810,7 +7815,7 @@
addErrorToDropBox(
eventType, r, processName, null, null, null, null, null, null, crashInfo,
- new Float(loadingProgress), incrementalMetrics);
+ new Float(loadingProgress), incrementalMetrics, null);
mAppErrors.crashApplication(r, crashInfo);
}
@@ -7993,7 +7998,7 @@
callingPid, (r != null) ? r.getProcessClassEnum() : 0);
addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo,
- null, null);
+ null, null, null);
return r;
}
@@ -8018,7 +8023,7 @@
for (Pair<String, ApplicationErrorReport.CrashInfo> p = list.poll();
p != null; p = list.poll()) {
addErrorToDropBox("wtf", proc, "system_server", null, null, null, p.first, null, null,
- p.second, null, null);
+ p.second, null, null, null);
}
}
@@ -8109,13 +8114,15 @@
* @param crashInfo giving an application stack trace, null if absent
* @param loadingProgress the loading progress of an installed package, range in [0, 1].
* @param incrementalMetrics metrics for apps installed on Incremental.
+ * @param errorId a unique id to append to the dropbox headers.
*/
public void addErrorToDropBox(String eventType,
ProcessRecord process, String processName, String activityShortComponentName,
String parentShortComponentName, ProcessRecord parentProcess,
String subject, final String report, final File dataFile,
final ApplicationErrorReport.CrashInfo crashInfo,
- @Nullable Float loadingProgress, @Nullable IncrementalMetrics incrementalMetrics) {
+ @Nullable Float loadingProgress, @Nullable IncrementalMetrics incrementalMetrics,
+ @Nullable UUID errorId) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
@@ -8169,6 +8176,9 @@
if (subject != null) {
sb.append("Subject: ").append(subject).append("\n");
}
+ if (errorId != null) {
+ sb.append("ErrorId: ").append(errorId.toString()).append("\n");
+ }
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
if (Debug.isDebuggerConnected()) {
sb.append("Debugger: Connected\n");
@@ -16741,19 +16751,20 @@
}
@Override
- public int checkOperation(int code, int uid, String packageName, boolean raw,
- QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
+ public int checkOperation(int code, int uid, String packageName,
+ String attributionTag, boolean raw,
+ QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
if (uid == mTargetUid && isTargetOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, shellUid, "com.android.shell", raw);
+ return superImpl.apply(code, shellUid, "com.android.shell", null, raw);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(code, uid, packageName, raw);
+ return superImpl.apply(code, uid, packageName, attributionTag, raw);
}
@Override
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 074e8fe..74094e5 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1627,7 +1627,7 @@
dropBuilder.append(catSw.toString());
FrameworkStatsLog.write(FrameworkStatsLog.LOW_MEM_REPORTED);
mService.addErrorToDropBox("lowmem", null, "system_server", null,
- null, null, tag.toString(), dropBuilder.toString(), null, null, null, null);
+ null, null, tag.toString(), dropBuilder.toString(), null, null, null, null, null);
synchronized (mService) {
long now = SystemClock.uptimeMillis();
if (mLastMemUsageReportTime < now) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 709139e..4629d0b 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -881,7 +881,10 @@
@GuardedBy({"mAm", "mProcLock"})
void freezeAppAsyncLSP(ProcessRecord app) {
- mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
+ if (mFreezeHandler.hasMessages(SET_FROZEN_PROCESS_MSG, app)) {
+ // Skip redundant DO_FREEZE message
+ return;
+ }
mFreezeHandler.sendMessageDelayed(
mFreezeHandler.obtainMessage(
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 1e04154..4ad9909 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -694,6 +694,8 @@
boolean containsCycle = collectReachableProcessesLocked(mPendingProcessSet,
processes, uids);
+ // Clear the pending set as they should've been included in 'processes'.
+ mPendingProcessSet.clear();
// Reset the flag
state.setReachable(false);
// Remove this app from the return list because we've done the computation on it.
@@ -767,10 +769,6 @@
}
queue.offer(service);
service.mState.setReachable(true);
- // During scanning the reachable dependants, remove them from the pending oomadj
- // targets list if it's possible, as they've been added into the immediate
- // oomadj targets list 'processes' above.
- mPendingProcessSet.remove(service);
}
final ProcessProviderRecord ppr = pr.mProviders;
for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
@@ -786,10 +784,6 @@
}
queue.offer(provider);
provider.mState.setReachable(true);
- // During scanning the reachable dependants, remove them from the pending oomadj
- // targets list if it's possible, as they've been added into the immediate
- // oomadj targets list 'processes' above.
- mPendingProcessSet.remove(provider);
}
}
@@ -887,11 +881,11 @@
final ArrayList<ProcessRecord> processes = mTmpProcessList;
final ActiveUids uids = mTmpUidRecords;
collectReachableProcessesLocked(mPendingProcessSet, processes, uids);
+ mPendingProcessSet.clear();
synchronized (mProcLock) {
updateOomAdjInnerLSP(oomAdjReason, topApp, processes, uids, true, false);
}
processes.clear();
- mPendingProcessSet.clear();
mService.mOomAdjProfiler.oomAdjEnded();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 88bd010..66d4779 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -55,7 +55,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-
+import java.util.UUID;
/**
* The error state of the process, such as if it's crashing/ANR etc.
*/
@@ -235,6 +235,7 @@
final boolean isSilentAnr;
final int pid = mApp.getPid();
+ final UUID errorId;
synchronized (mService) {
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
if (mService.mAtmInternal.isShuttingDown()) {
@@ -264,6 +265,13 @@
EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName,
mApp.info.flags, annotation);
+ if (mService.mTraceErrorLogger.isAddErrorIdEnabled()) {
+ errorId = mService.mTraceErrorLogger.generateErrorId();
+ mService.mTraceErrorLogger.addErrorIdToTrace(errorId);
+ } else {
+ errorId = null;
+ }
+
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(pid);
@@ -315,6 +323,9 @@
&& parentShortComponentName.equals(activityShortComponentName)) {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
+ if (errorId != null) {
+ info.append("ErrorId: ").append(errorId.toString()).append("\n");
+ }
// Retrieve controller with max ANR delay from AnrControllers
// Note that we retrieve the controller before dumping stacks because dumping stacks can
@@ -457,7 +468,7 @@
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
parentShortComponentName, parentPr, annotation, report.toString(), tracesFile,
- null, new Float(loadingProgress), incrementalMetrics);
+ null, new Float(loadingProgress), incrementalMetrics, errorId);
if (mApp.getWindowProcessController().appNotResponding(info.toString(),
() -> {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0d19209e..0ffaccf 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -802,7 +802,7 @@
mAppDataIsolationEnabled =
SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
- ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mAppDataIsolationAllowlistedApps = new ArrayList<>(
SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 801e382..6429b79 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -25,6 +25,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
@@ -1216,7 +1217,6 @@
mAllowStartFgs = mAllowStartFgsByPermission = ret;
}
- // TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
@GuardedBy("mService")
void setAllowStartFgs() {
if (mAllowStartFgs != REASON_DENIED) {
@@ -1238,6 +1238,16 @@
}
if (mAllowStartFgs == REASON_DENIED) {
+ if (mService.mInternal != null) {
+ final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp(
+ UserHandle.getUserId(mApp.info.uid), mApp.info.uid);
+ if (isCompanionApp) {
+ mAllowStartFgs = REASON_COMPANION_DEVICE_MANAGER;
+ }
+ }
+ }
+
+ if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a profile owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
diff --git a/services/core/java/com/android/server/am/TraceErrorLogger.java b/services/core/java/com/android/server/am/TraceErrorLogger.java
new file mode 100644
index 0000000..f055be2
--- /dev/null
+++ b/services/core/java/com/android/server/am/TraceErrorLogger.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.os.Trace;
+import android.provider.DeviceConfig;
+
+import java.util.UUID;
+
+/**
+ * Adds a unique id to a trace.
+ *
+ * @hide
+ */
+class TraceErrorLogger {
+ private static final String COUNTER_PREFIX = "ErrorId:";
+ private static final String ADD_ERROR_ID = "add_error_id";
+ private static final int PLACEHOLDER_VALUE = 1;
+
+ public boolean isAddErrorIdEnabled() {
+ return DeviceConfig
+ .getBoolean(DeviceConfig.NAMESPACE_TRACE_ERROR_LOGGER, ADD_ERROR_ID,
+ false);
+ }
+
+ /**
+ * Generates a unique id with which to tag a trace.
+ */
+ public UUID generateErrorId() {
+ return UUID.randomUUID();
+ }
+
+ /**
+ * Pushes a counter containing a unique id and a label {@link #COUNTER_PREFIX} so that traces
+ * can be uniquely identified. We also add the same id to the dropbox entry of the error, so
+ * that we can join the trace and the error server-side.
+ *
+ * @param errorId The unique id with which to tag the trace.
+ */
+ public void addErrorIdToTrace(UUID errorId) {
+ Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER, COUNTER_PREFIX + errorId.toString(),
+ PLACEHOLDER_VALUE);
+ }
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 13dc444..b6aec836 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3063,16 +3063,20 @@
}
@Override
- public int checkOperationRaw(int code, int uid, String packageName) {
- return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, true /*raw*/);
+ public int checkOperationRaw(int code, int uid, String packageName,
+ @Nullable String attributionTag) {
+ return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
+ true /*raw*/);
}
@Override
public int checkOperation(int code, int uid, String packageName) {
- return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, false /*raw*/);
+ return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
+ false /*raw*/);
}
- private int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
+ private int checkOperationImpl(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
verifyIncomingOp(code);
verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
@@ -3080,7 +3084,7 @@
if (resolvedPackageName == null) {
return AppOpsManager.MODE_IGNORED;
}
- return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
+ return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag, raw);
}
/**
@@ -3094,7 +3098,7 @@
* @return The mode of the op
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
- boolean raw) {
+ @Nullable String attributionTag, boolean raw) {
RestrictionBypass bypass;
try {
bypass = verifyAndGetBypass(uid, packageName, null);
@@ -3107,7 +3111,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -3326,7 +3330,7 @@
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
- if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
@@ -3813,7 +3817,7 @@
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final UidState uidState = ops.uidState;
- isRestricted = isOpRestrictedLocked(uid, code, packageName, bypass);
+ isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass);
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
@@ -4555,7 +4559,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- @Nullable RestrictionBypass appBypass) {
+ String attributionTag, @Nullable RestrictionBypass appBypass) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -4563,7 +4567,7 @@
// For each client, check that the given op is not restricted, or that the given
// package is exempt from the restriction.
ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
- if (restrictionState.hasRestriction(code, packageName, userHandle)) {
+ if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
if (opBypass != null) {
// If we are the system, bypass user restrictions for certain codes
@@ -6177,25 +6181,20 @@
}
}
- final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
- ? restrictionState.perUserExcludedPackages.size() : 0;
+ final int excludedPackageCount = restrictionState.perUserExcludedPackageTags != null
+ ? restrictionState.perUserExcludedPackageTags.size() : 0;
if (excludedPackageCount > 0 && dumpOp < 0) {
boolean printedPackagesHeader = false;
for (int j = 0; j < excludedPackageCount; j++) {
- int userId = restrictionState.perUserExcludedPackages.keyAt(j);
- String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
+ int userId = restrictionState.perUserExcludedPackageTags.keyAt(j);
+ Map<String, String[]> packageNames =
+ restrictionState.perUserExcludedPackageTags.valueAt(j);
if (packageNames == null) {
continue;
}
boolean hasPackage;
if (dumpPackage != null) {
- hasPackage = false;
- for (String pkg : packageNames) {
- if (dumpPackage.equals(pkg)) {
- hasPackage = true;
- break;
- }
- }
+ hasPackage = packageNames.containsKey(dumpPackage);
} else {
hasPackage = true;
}
@@ -6210,8 +6209,24 @@
pw.println(" Excluded packages:");
printedPackagesHeader = true;
}
- pw.print(" "); pw.print("user: "); pw.print(userId);
- pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
+ pw.print(" ");
+ pw.print("user: ");
+ pw.print(userId);
+ pw.println(" packages: ");
+ for (Map.Entry<String, String[]> entry : packageNames.entrySet()) {
+ if (entry.getValue() == null) {
+ continue;
+ }
+ pw.print(" ");
+ pw.print(entry.getKey());
+ pw.print(": ");
+ if (entry.getValue().length == 0) {
+ pw.print("*");
+ } else {
+ pw.print(Arrays.toString(entry.getValue()));
+ }
+ pw.println();
+ }
}
}
}
@@ -6245,7 +6260,7 @@
@Override
public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
- String[] exceptionPackages) {
+ Map<String, String[]> excludedPackageTags) {
if (Binder.getCallingPid() != Process.myPid()) {
mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -6261,11 +6276,11 @@
}
verifyIncomingOp(code);
Objects.requireNonNull(token);
- setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
+ setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
}
private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
- int userHandle, String[] exceptionPackages) {
+ int userHandle, Map<String, String[]> excludedPackageTags) {
synchronized (AppOpsService.this) {
ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
@@ -6278,7 +6293,8 @@
mOpUserRestrictions.put(token, restrictionState);
}
- if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+ if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
+ userHandle)) {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
mHandler.sendMessage(PooledLambda.obtainMessage(
@@ -6454,6 +6470,7 @@
"offsetHistory");
// Must not hold the appops lock
mHistoricalRegistry.offsetHistory(offsetMillis);
+ mHistoricalRegistry.offsetDiscreteHistory(offsetMillis);
}
@Override
@@ -6808,7 +6825,7 @@
private final class ClientRestrictionState implements DeathRecipient {
private final IBinder token;
SparseArray<boolean[]> perUserRestrictions;
- SparseArray<String[]> perUserExcludedPackages;
+ SparseArray<Map<String, String[]>> perUserExcludedPackageTags;
public ClientRestrictionState(IBinder token)
throws RemoteException {
@@ -6817,7 +6834,7 @@
}
public boolean setRestriction(int code, boolean restricted,
- String[] excludedPackages, int userId) {
+ Map<String, String[]> excludedPackageTags, int userId) {
boolean changed = false;
if (perUserRestrictions == null && restricted) {
@@ -6859,19 +6876,27 @@
}
if (userRestrictions != null) {
- final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
- if (perUserExcludedPackages == null && !noExcludedPackages) {
- perUserExcludedPackages = new SparseArray<>();
+ final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackageTags);
+ if (perUserExcludedPackageTags == null && !noExcludedPackages) {
+ perUserExcludedPackageTags = new SparseArray<>();
}
- if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
- perUserExcludedPackages.get(thisUserId))) {
+ if (perUserExcludedPackageTags != null) {
if (noExcludedPackages) {
- perUserExcludedPackages.remove(thisUserId);
- if (perUserExcludedPackages.size() <= 0) {
- perUserExcludedPackages = null;
+ perUserExcludedPackageTags.remove(thisUserId);
+ if (perUserExcludedPackageTags.size() <= 0) {
+ perUserExcludedPackageTags = null;
}
} else {
- perUserExcludedPackages.put(thisUserId, excludedPackages);
+ Map<String, String[]> userExcludedPackageTags =
+ perUserExcludedPackageTags.get(thisUserId);
+ if (userExcludedPackageTags == null) {
+ userExcludedPackageTags = new ArrayMap<>(
+ excludedPackageTags.size());
+ perUserExcludedPackageTags.put(thisUserId,
+ userExcludedPackageTags);
+ }
+ userExcludedPackageTags.clear();
+ userExcludedPackageTags.putAll(excludedPackageTags);
}
changed = true;
}
@@ -6882,7 +6907,8 @@
return changed;
}
- public boolean hasRestriction(int restriction, String packageName, int userId) {
+ public boolean hasRestriction(int restriction, String packageName, String attributionTag,
+ int userId) {
if (perUserRestrictions == null) {
return false;
}
@@ -6893,21 +6919,29 @@
if (!restrictions[restriction]) {
return false;
}
- if (perUserExcludedPackages == null) {
+ if (perUserExcludedPackageTags == null) {
return true;
}
- String[] perUserExclusions = perUserExcludedPackages.get(userId);
+ Map<String, String[]> perUserExclusions = perUserExcludedPackageTags.get(userId);
if (perUserExclusions == null) {
return true;
}
- return !ArrayUtils.contains(perUserExclusions, packageName);
+ String[] excludedTags = perUserExclusions.get(packageName);
+ if (excludedTags == null) {
+ return true;
+ }
+ if (excludedTags.length == 0) {
+ // all attribution tags within the package are excluded
+ return false;
+ }
+ return !ArrayUtils.contains(excludedTags, attributionTag);
}
public void removeUser(int userId) {
- if (perUserExcludedPackages != null) {
- perUserExcludedPackages.remove(userId);
- if (perUserExcludedPackages.size() <= 0) {
- perUserExcludedPackages = null;
+ if (perUserExcludedPackageTags != null) {
+ perUserExcludedPackageTags.remove(userId);
+ if (perUserExcludedPackageTags.size() <= 0) {
+ perUserExcludedPackageTags = null;
}
}
if (perUserRestrictions != null) {
@@ -7139,23 +7173,25 @@
return mCheckOpsDelegate;
}
- public int checkOperation(int code, int uid, String packageName, boolean raw) {
+ public int checkOperation(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
- return mPolicy.checkOperation(code, uid, packageName, raw,
+ return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
this::checkDelegateOperationImpl);
} else {
- return mPolicy.checkOperation(code, uid, packageName, raw,
+ return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
AppOpsService.this::checkOperationImpl);
}
} else if (mCheckOpsDelegate != null) {
- return checkDelegateOperationImpl(code, uid, packageName, raw);
+ return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw);
}
- return checkOperationImpl(code, uid, packageName, raw);
+ return checkOperationImpl(code, uid, packageName, attributionTag, raw);
}
- private int checkDelegateOperationImpl(int code, int uid, String packageName, boolean raw) {
- return mCheckOpsDelegate.checkOperation(code, uid, packageName, raw,
+ private int checkDelegateOperationImpl(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
+ return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw,
AppOpsService.this::checkOperationImpl);
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 35e8d34..0ab6c4a 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -212,6 +212,7 @@
}
void systemReady(@NonNull ContentResolver resolver) {
+ mDiscreteRegistry.systemReady();
final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
resolver.registerContentObserver(uri, false, new ContentObserver(
FgThread.getHandler()) {
@@ -249,7 +250,6 @@
}
}
}
- mDiscreteRegistry.systemReady();
}
private boolean isPersistenceInitializedMLocked() {
@@ -594,6 +594,9 @@
mPersistence.persistHistoricalOpsDLocked(history);
}
}
+ }
+
+ void offsetDiscreteHistory(long offsetMillis) {
mDiscreteRegistry.offsetHistory(offsetMillis);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a3c5904..136916a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -413,6 +413,26 @@
AudioSystem.STREAM_MUSIC, // STREAM_ACCESSIBILITY
AudioSystem.STREAM_MUSIC // STREAM_ASSISTANT
};
+ /**
+ * Using Volume groups configuration allows to control volume per attributes
+ * and group definition may differ from stream aliases.
+ * So, do not alias any stream on one another when using volume groups.
+ * TODO(b/181140246): volume group definition hosting alias definition.
+ */
+ private final int[] STREAM_VOLUME_ALIAS_NONE = new int[] {
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
+ AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM
+ AudioSystem.STREAM_RING, // STREAM_RING
+ AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
+ AudioSystem.STREAM_ALARM, // STREAM_ALARM
+ AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION
+ AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
+ AudioSystem.STREAM_SYSTEM_ENFORCED, // STREAM_SYSTEM_ENFORCED
+ AudioSystem.STREAM_DTMF, // STREAM_DTMF
+ AudioSystem.STREAM_TTS, // STREAM_TTS
+ AudioSystem.STREAM_ACCESSIBILITY, // STREAM_ACCESSIBILITY
+ AudioSystem.STREAM_ASSISTANT // STREAM_ASSISTANT
+ };
private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
AudioSystem.STREAM_RING, // STREAM_SYSTEM
@@ -428,6 +448,7 @@
AudioSystem.STREAM_MUSIC // STREAM_ASSISTANT
};
protected static int[] mStreamVolumeAlias;
+ private static final int UNSET_INDEX = -1;
/**
* Map AudioSystem.STREAM_* constants to app ops. This should be used
@@ -449,6 +470,7 @@
};
private final boolean mUseFixedVolume;
+ private final boolean mUseVolumeGroupAliases;
// If absolute volume is supported in AVRCP device
private volatile boolean mAvrcpAbsVolSupported = false;
@@ -849,6 +871,9 @@
mSupportsMicPrivacyToggle = context.getSystemService(SensorPrivacyManager.class)
.supportsSensorToggle(SensorPrivacyManager.Sensors.MICROPHONE);
+ mUseVolumeGroupAliases = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups);
+
// Initialize volume
// Priority 1 - Android Property
// Priority 2 - Audio Policy Service
@@ -869,6 +894,12 @@
MIN_STREAM_VOLUME[streamType] = minVolume;
}
}
+ if (mUseVolumeGroupAliases) {
+ // Set all default to uninitialized.
+ for (int stream = 0; stream < AudioSystem.DEFAULT_STREAM_VOLUME.length; stream++) {
+ AudioSystem.DEFAULT_STREAM_VOLUME[stream] = UNSET_INDEX;
+ }
+ }
}
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
@@ -1705,18 +1736,42 @@
updateDefaultVolumes();
}
- // Update default indexes from aliased streams. Must be called after mStreamStates is created
+ /**
+ * Update default indexes from aliased streams. Must be called after mStreamStates is created
+ * TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for default
+ * index. Need to make default index configurable and independent of streams.
+ * Fallback on music stream for default initialization to take benefit of property based default
+ * initialization.
+ * For other volume groups not linked to any streams, default music stream index is considered.
+ */
private void updateDefaultVolumes() {
for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (stream != mStreamVolumeAlias[stream]) {
- AudioSystem.DEFAULT_STREAM_VOLUME[stream] = (rescaleIndex(
- AudioSystem.DEFAULT_STREAM_VOLUME[mStreamVolumeAlias[stream]] * 10,
- mStreamVolumeAlias[stream],
- stream) + 5) / 10;
+ int streamVolumeAlias = mStreamVolumeAlias[stream];
+ if (mUseVolumeGroupAliases) {
+ if (AudioSystem.DEFAULT_STREAM_VOLUME[stream] != UNSET_INDEX) {
+ // Already initialized through default property based mecanism.
+ continue;
+ }
+ streamVolumeAlias = AudioSystem.STREAM_MUSIC;
+ int defaultAliasVolume = getUiDefaultRescaledIndex(streamVolumeAlias, stream);
+ if ((defaultAliasVolume >= MIN_STREAM_VOLUME[stream])
+ && (defaultAliasVolume <= MAX_STREAM_VOLUME[stream])) {
+ AudioSystem.DEFAULT_STREAM_VOLUME[stream] = defaultAliasVolume;
+ continue;
+ }
+ }
+ if (stream != streamVolumeAlias) {
+ AudioSystem.DEFAULT_STREAM_VOLUME[stream] =
+ getUiDefaultRescaledIndex(streamVolumeAlias, stream);
}
}
}
+ private int getUiDefaultRescaledIndex(int srcStream, int dstStream) {
+ return (rescaleIndex(AudioSystem.DEFAULT_STREAM_VOLUME[srcStream] * 10,
+ srcStream, dstStream) + 5) / 10;
+ }
+
private void dumpStreamStates(PrintWriter pw) {
pw.println("\nStream volumes (device: index)");
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -1740,6 +1795,9 @@
if (mIsSingleVolume) {
mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
+ } else if (mUseVolumeGroupAliases) {
+ mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NONE;
+ dtmfStreamAlias = AudioSystem.STREAM_DTMF;
} else {
switch (mPlatformType) {
case AudioSystem.PLATFORM_VOICE:
@@ -2768,7 +2826,7 @@
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
- (streamTypeAlias == getUiSoundsStreamType())) {
+ (isUiSoundsStreamType(streamTypeAlias))) {
int ringerMode = getRingerModeInternal();
// do not vibrate if already in vibrate mode
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
@@ -3570,7 +3628,7 @@
case Settings.Global.ZEN_MODE_ALARMS:
case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
return !isStreamMutedByRingerOrZenMode(streamTypeAlias)
- || streamTypeAlias == getUiSoundsStreamType()
+ || isUiSoundsStreamType(streamTypeAlias)
|| (flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0;
}
@@ -3987,9 +4045,26 @@
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
}
- /** @see AudioManager#getUiSoundsStreamType() */
+ /** @see AudioManager#getUiSoundsStreamType()
+ * TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
+ * UI Sounds identification.
+ * Fallback on Voice configuration to ensure correct behavior of DnD feature.
+ */
public int getUiSoundsStreamType() {
- return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
+ return mUseVolumeGroupAliases ? STREAM_VOLUME_ALIAS_VOICE[AudioSystem.STREAM_SYSTEM]
+ : mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
+ }
+
+ /**
+ * TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
+ * UI Sounds identification.
+ * Fallback on Voice configuration to ensure correct behavior of DnD feature.
+ */
+ private boolean isUiSoundsStreamType(int aliasStreamType) {
+ return mUseVolumeGroupAliases
+ ? STREAM_VOLUME_ALIAS_VOICE[aliasStreamType]
+ == STREAM_VOLUME_ALIAS_VOICE[AudioSystem.STREAM_SYSTEM]
+ : aliasStreamType == mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
}
/** @see AudioManager#setMicrophoneMute(boolean) */
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index ab67b13..093ecd5 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -379,7 +379,15 @@
return null;
}
synchronized (mLock) {
- addActiveOwnerLocked(intendingUid, pkg);
+ try {
+ addActiveOwnerLocked(intendingUid, pkg);
+ } catch (SecurityException e) {
+ // Permission could not be granted - URI may be invalid
+ Slog.i(TAG, "Could not grant permission to primary clip. Clearing clipboard.");
+ setPrimaryClipInternalLocked(null, intendingUid, pkg);
+ return null;
+ }
+
PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
notifyTextClassifierLocked(clipboard, pkg, intendingUid);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 40ab108..7cb2921 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -93,6 +93,7 @@
private int mDisplayHeight; // real height, not rotated
private SurfaceControl mSurfaceControl;
private Surface mSurface;
+ private SurfaceControl mBLASTSurfaceControl;
private BLASTBufferQueue mBLASTBufferQueue;
private NaturalSurfaceLayout mSurfaceLayout;
private EGLDisplay mEglDisplay;
@@ -576,7 +577,7 @@
if (mMode == MODE_FADE) {
builder.setColorLayer();
} else {
- builder.setBLASTLayer();
+ builder.setContainerLayer();
}
mSurfaceControl = builder.build();
} catch (OutOfResourcesException ex) {
@@ -592,7 +593,14 @@
mTransaction.apply();
if (mMode != MODE_FADE) {
- mBLASTBufferQueue = new BLASTBufferQueue("ColorFade", mSurfaceControl,
+ final SurfaceControl.Builder b = new SurfaceControl.Builder()
+ .setName("ColorFade BLAST")
+ .setParent(mSurfaceControl)
+ .setHidden(false)
+ .setSecure(isSecure)
+ .setBLASTLayer();
+ mBLASTSurfaceControl = b.build();
+ mBLASTBufferQueue = new BLASTBufferQueue("ColorFade", mBLASTSurfaceControl,
mDisplayWidth, mDisplayHeight, PixelFormat.TRANSLUCENT);
mSurface = mBLASTBufferQueue.createSurface();
}
@@ -723,10 +731,16 @@
mTransaction.remove(mSurfaceControl).apply();
if (mSurface != null) {
mSurface.release();
- mBLASTBufferQueue.destroy();
mSurface = null;
+ }
+
+ if (mBLASTSurfaceControl != null) {
+ mBLASTSurfaceControl.release();
+ mBLASTSurfaceControl = null;
+ mBLASTBufferQueue.destroy();
mBLASTBufferQueue = null;
}
+
mSurfaceControl = null;
mSurfaceVisible = false;
mSurfaceAlpha = 0f;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 314955b..170564d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -422,7 +422,7 @@
if (configBrightnessDefault != null) {
mBrightnessDefault = configBrightnessDefault.floatValue();
} else {
- mBrightnessDefault = BRIGHTNESS_DEFAULT;
+ loadBrightnessDefaultFromConfigXml();
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 4ad8797..52b05f2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1362,6 +1362,9 @@
+ mBrightnessReasonTemp.toString(brightnessAdjustmentFlags)
+ "', previous reason: '" + mBrightnessReason + "'.");
mBrightnessReason.set(mBrightnessReasonTemp);
+ } else if (mBrightnessReasonTemp.reason == BrightnessReason.REASON_MANUAL
+ && userSetBrightnessChanged) {
+ Slog.v(TAG, "Brightness [" + brightnessState + "] manual adjustment.");
}
// Update display white-balance.
@@ -2021,7 +2024,8 @@
|| mPendingScreenBrightnessSetting < 0.0f)) {
return false;
}
- if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
+ if (BrightnessSynchronizer.floatEquals(
+ mCurrentScreenBrightnessSetting, mPendingScreenBrightnessSetting)) {
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
return 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 dc3dc46..ae9c64b4 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.graphics.Typeface;
import android.graphics.fonts.FontFamily;
@@ -61,7 +62,9 @@
private static final String TAG = "FontManagerService";
private static final String FONT_FILES_DIR = "/data/fonts/files";
+ private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
+ @RequiresPermission(Manifest.permission.UPDATE_FONTS)
@Override
public FontConfig getFontConfig() {
getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
@@ -69,28 +72,38 @@
return getSystemFontConfig();
}
+ @RequiresPermission(Manifest.permission.UPDATE_FONTS)
@Override
public int updateFontFamily(@NonNull List<FontUpdateRequest> requests, int baseVersion) {
- Preconditions.checkArgumentNonnegative(baseVersion);
- Objects.requireNonNull(requests);
- getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
- "UPDATE_FONTS permission required.");
try {
- update(baseVersion, requests);
- return FontManager.RESULT_SUCCESS;
- } catch (SystemFontException e) {
- Slog.e(TAG, "Failed to update font family", e);
- return e.getErrorCode();
+ Preconditions.checkArgumentNonnegative(baseVersion);
+ Objects.requireNonNull(requests);
+ getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
+ "UPDATE_FONTS permission required.");
+ try {
+ update(baseVersion, requests);
+ return FontManager.RESULT_SUCCESS;
+ } catch (SystemFontException e) {
+ Slog.e(TAG, "Failed to update font family", e);
+ return e.getErrorCode();
+ }
} finally {
- for (FontUpdateRequest request : requests) {
- ParcelFileDescriptor fd = request.getFd();
- if (fd != null) {
- try {
- fd.close();
- } catch (IOException e) {
- Slog.w(TAG, "Failed to close fd", e);
- }
- }
+ closeFileDescriptors(requests);
+ }
+ }
+
+ private static void closeFileDescriptors(@Nullable List<FontUpdateRequest> requests) {
+ // Make sure we close every passed FD, even if 'requests' is constructed incorrectly and
+ // some fields are null.
+ if (requests == null) return;
+ for (FontUpdateRequest request : requests) {
+ if (request == null) continue;
+ ParcelFileDescriptor fd = request.getFd();
+ if (fd == null) continue;
+ try {
+ fd.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to close fd", e);
}
}
}
@@ -118,9 +131,9 @@
public static final class Lifecycle extends SystemService {
private final FontManagerService mService;
- public Lifecycle(@NonNull Context context) {
+ public Lifecycle(@NonNull Context context, boolean safeMode) {
super(context);
- mService = new FontManagerService(context);
+ mService = new FontManagerService(context, safeMode);
}
@Override
@@ -175,18 +188,24 @@
@Nullable
private SharedMemory mSerializedFontMap = null;
- private FontManagerService(Context context) {
+ private FontManagerService(Context context, boolean safeMode) {
+ if (safeMode) {
+ Slog.i(TAG, "Entering safe mode. Deleting all font updates.");
+ UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
+ }
mContext = context;
- mUpdatableFontDir = createUpdatableFontDir();
+ mUpdatableFontDir = createUpdatableFontDir(safeMode);
initialize();
}
@Nullable
- private static UpdatableFontDir createUpdatableFontDir() {
+ private static UpdatableFontDir createUpdatableFontDir(boolean safeMode) {
+ // Never read updatable font files in safe mode.
+ if (safeMode) return null;
// If apk verity is supported, fs-verity should be available.
if (!VerityUtils.isFsVeritySupported()) return null;
- return new UpdatableFontDir(new File(FONT_FILES_DIR),
- new OtfFontFileParser(), new FsverityUtilImpl());
+ return new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser(),
+ new FsverityUtilImpl(), new File(CONFIG_XML_FILE));
}
private void initialize() {
@@ -231,18 +250,23 @@
}
}
- /* package */ void clearUpdates() throws SystemFontException {
- if (mUpdatableFontDir == null) {
- throw new SystemFontException(
- FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
- "The font updater is disabled.");
- }
- synchronized (mUpdatableFontDirLock) {
- mUpdatableFontDir.clearUpdates();
- updateSerializedFontMap();
- }
+ /**
+ * Clears all updates and restarts FontManagerService.
+ *
+ * <p>CAUTION: this method is not safe. Existing processes may crash due to missing font files.
+ * This method is only for {@link FontManagerShellCommand}.
+ */
+ /* package */ void clearUpdates() {
+ UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
+ initialize();
}
+ /**
+ * Restarts FontManagerService, removing not-the-latest font files.
+ *
+ * <p>CAUTION: this method is not safe. Existing processes may crash due to missing font files.
+ * This method is only for {@link FontManagerShellCommand}.
+ */
/* package */ void restart() {
initialize();
}
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 e4928ce..3fecef7 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -448,7 +448,7 @@
}
}
- private int clear(ShellCommand shell) throws SystemFontException {
+ private int clear(ShellCommand shell) {
mService.clearUpdates();
shell.getOutPrintWriter().println("Success");
return 0;
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 981cc838..743b4d9 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -59,8 +59,6 @@
private static final String TAG = "UpdatableFontDir";
private static final String RANDOM_DIR_PREFIX = "~~";
- private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
-
/** Interface to mock font file access in tests. */
interface FontFileParser {
String getPostScriptName(File file) throws IOException;
@@ -139,8 +137,9 @@
*/
private final ArrayMap<String, FontFileInfo> mFontFileInfoMap = new ArrayMap<>();
- UpdatableFontDir(File filesDir, FontFileParser parser, FsverityUtil fsverityUtil) {
- this(filesDir, parser, fsverityUtil, new File(CONFIG_XML_FILE),
+ UpdatableFontDir(File filesDir, FontFileParser parser, FsverityUtil fsverityUtil,
+ File configFile) {
+ this(filesDir, parser, fsverityUtil, configFile,
System::currentTimeMillis,
(map) -> SystemFonts.getSystemFontConfig(map, 0, 0)
);
@@ -215,17 +214,6 @@
}
}
- /* package */ void clearUpdates() throws SystemFontException {
- mFontFileInfoMap.clear();
- FileUtils.deleteContents(mFilesDir);
-
- mLastModifiedMillis = mCurrentTimeSupplier.get();
- PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedMillis = mLastModifiedMillis;
- writePersistentConfig(config);
- mConfigVersion++;
- }
-
/**
* Applies multiple {@link FontUpdateRequest}s in transaction.
* If one of the request fails, the fonts and config are rolled back to the previous state
@@ -616,4 +604,19 @@
}
return familyMap;
}
+
+ /* package */ static void deleteAllFiles(File filesDir, File configFile) {
+ // As this method is called in safe mode, try to delete all files even though an exception
+ // is thrown.
+ try {
+ new AtomicFile(configFile).delete();
+ } catch (Throwable t) {
+ Slog.w(TAG, "Failed to delete " + configFile);
+ }
+ try {
+ FileUtils.deleteContents(filesDir);
+ } catch (Throwable t) {
+ Slog.w(TAG, "Failed to delete " + filesDir);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 518c428..94e669a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5761,6 +5761,7 @@
final String imeId = shellCommand.getNextArgRequired();
final PrintWriter out = shellCommand.getOutPrintWriter();
final PrintWriter error = shellCommand.getErrPrintWriter();
+ boolean hasFailed = false;
synchronized (mMethodMap) {
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
@@ -5768,11 +5769,11 @@
if (!userHasDebugPriv(userId, shellCommand)) {
continue;
}
- handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
- out, error);
+ hasFailed |= !handleShellCommandEnableDisableInputMethodInternalLocked(
+ userId, imeId, enabled, out, error);
}
}
- return ShellCommandResult.SUCCESS;
+ return hasFailed ? ShellCommandResult.FAILURE : ShellCommandResult.SUCCESS;
}
/**
@@ -5804,8 +5805,18 @@
return UserHandle.USER_CURRENT;
}
+ /**
+ * Handles core logic of {@code adb shell ime enable} and {@code adb shell ime disable}.
+ *
+ * @param userId user ID specified to the command. Pseudo user IDs are not supported.
+ * @param imeId IME ID specified to the command.
+ * @param enabled {@code true} for {@code adb shell ime enable}. {@code false} otherwise.
+ * @param out {@link PrintWriter} to output standard messages.
+ * @param error {@link PrintWriter} to output error messages.
+ * @return {@code false} if it fails to enable the IME. {@code false} otherwise.
+ */
@BinderThread
- private void handleShellCommandEnableDisableInputMethodInternalLocked(
+ private boolean handleShellCommandEnableDisableInputMethodInternalLocked(
@UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
PrintWriter error) {
boolean failedToEnableUnknownIme = false;
@@ -5851,15 +5862,20 @@
error.print("Unknown input method ");
error.print(imeId);
error.println(" cannot be enabled for user #" + userId);
- } else {
- out.print("Input method ");
- out.print(imeId);
- out.print(": ");
- out.print((enabled == previouslyEnabled) ? "already " : "now ");
- out.print(enabled ? "enabled" : "disabled");
- out.print(" for user #");
- out.println(userId);
+ // Also print this failure into logcat for better debuggability.
+ Slog.e(TAG, "\"ime enable " + imeId + "\" for user #" + userId
+ + " failed due to its unrecognized IME ID.");
+ return false;
}
+
+ out.print("Input method ");
+ out.print(imeId);
+ out.print(": ");
+ out.print((enabled == previouslyEnabled) ? "already " : "now ");
+ out.print(enabled ? "enabled" : "disabled");
+ out.print(" for user #");
+ out.println(userId);
+ return true;
}
/**
@@ -5874,6 +5890,7 @@
final String imeId = shellCommand.getNextArgRequired();
final PrintWriter out = shellCommand.getOutPrintWriter();
final PrintWriter error = shellCommand.getErrPrintWriter();
+ boolean hasFailed = false;
synchronized (mMethodMap) {
final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
@@ -5887,15 +5904,19 @@
error.print(imeId);
error.print(" cannot be selected for user #");
error.println(userId);
+ // Also print this failure into logcat for better debuggability.
+ Slog.e(TAG, "\"ime set " + imeId + "\" for user #" + userId
+ + " failed due to its unrecognized IME ID.");
} else {
out.print("Input method ");
out.print(imeId);
out.print(" selected for user #");
out.println(userId);
}
+ hasFailed |= failedToSelectUnknownIme;
}
}
- return ShellCommandResult.SUCCESS;
+ return hasFailed ? ShellCommandResult.FAILURE : ShellCommandResult.SUCCESS;
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 2969e53..c340a2b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -196,7 +196,7 @@
final int numImes = imis.size();
for (int i = 0; i < numImes; ++i) {
final InputMethodInfo imi = imis.get(i);
- if (forImeMenu && !imi.showInInputMethodPicker()) {
+ if (forImeMenu && !imi.shouldShowInInputMethodPicker()) {
continue;
}
final List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList =
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 8829fa9..1e8d904 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -139,6 +139,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -1405,21 +1406,28 @@
Preconditions.checkArgument(userId >= 0);
-
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
- String[] allowedPackages = null;
+ ArrayMap<String, String[]> allowedPackages = null;
if (!enabled) {
- ArraySet<String> packages = new ArraySet<>();
+ ArrayMap<String, ArraySet<String>> packages = new ArrayMap<>();
for (LocationProviderManager manager : mProviderManagers) {
CallerIdentity identity = manager.getIdentity();
if (identity != null) {
- packages.add(identity.getPackageName());
+ packages.computeIfAbsent(identity.getPackageName(), k -> new ArraySet<>()).add(
+ identity.getAttributionTag());
}
}
- packages.add(mContext.getPackageName());
- packages.addAll(mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist());
- allowedPackages = packages.toArray(new String[0]);
+ for (String packageName :
+ mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist()) {
+ packages.computeIfAbsent(packageName, k -> new ArraySet<>());
+ }
+ packages.computeIfAbsent(mContext.getPackageName(), k -> new ArraySet<>());
+
+ allowedPackages = new ArrayMap<>();
+ for (Map.Entry<String, ArraySet<String>> entry : packages.entrySet()) {
+ allowedPackages.put(entry.getKey(), entry.getValue().toArray(new String[0]));
+ }
}
AppOpsManager appOpsManager = Objects.requireNonNull(
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index 5dc3ed8..9378493 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -20,6 +20,7 @@
import android.location.Criteria;
import android.location.Location;
import android.location.provider.ProviderProperties;
+import android.os.SystemClock;
import android.os.UserHandle;
import com.android.modules.utils.BasicShellCommandHandler;
@@ -236,7 +237,7 @@
Location location = new Location(provider);
location.setAccuracy(DEFAULT_TEST_LOCATION_ACCURACY);
location.setTime(System.currentTimeMillis());
- location.setElapsedRealtimeNanos(System.nanoTime());
+ location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
do {
String option = getNextOption();
diff --git a/services/core/java/com/android/server/os/OWNERS b/services/core/java/com/android/server/os/OWNERS
new file mode 100644
index 0000000..1957332
--- /dev/null
+++ b/services/core/java/com/android/server/os/OWNERS
@@ -0,0 +1,2 @@
+# Bugreporting
+per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 1d73abc..8fc5fbe 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -288,7 +288,9 @@
if (targetUserProfiles.isEmpty()) {
return false;
}
- return hasCallerGotInteractAcrossProfilesPermission(callingPackage);
+ return hasCallerGotInteractAcrossProfilesPermission(callingPackage)
+ && haveProfilesGotInteractAcrossProfilesPermission(
+ callingPackage, targetUserProfiles);
}
private boolean hasCallerGotInteractAcrossProfilesPermission(String callingPackage) {
@@ -296,6 +298,28 @@
callingPackage, mInjector.getCallingUid(), mInjector.getCallingPid());
}
+ private boolean haveProfilesGotInteractAcrossProfilesPermission(
+ String packageName, List<UserHandle> profiles) {
+ for (UserHandle profile : profiles) {
+ final int uid = mInjector.withCleanCallingIdentity(() -> {
+ try {
+ return mInjector.getPackageManager().getPackageUidAsUser(
+ packageName, /* flags= */ 0, profile.getIdentifier());
+ } catch (PackageManager.NameNotFoundException e) {
+ return -1;
+ }
+ });
+ if (uid == -1) {
+ return false;
+ }
+ if (!hasInteractAcrossProfilesPermission(
+ packageName, uid, PermissionChecker.PID_UNKNOWN)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean isCrossProfilePackageAllowlisted(String packageName) {
return mInjector.withCleanCallingIdentity(() ->
mInjector.getDevicePolicyManagerInternal()
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index 7927538..9ea16d3 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.content.IntentFilter;
-import com.android.server.WatchedIntentResolver;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6f4ec82..83eb093 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3762,13 +3762,6 @@
}
}
- final DataLoaderManager dataLoaderManager = mContext.getSystemService(
- DataLoaderManager.class);
- if (dataLoaderManager == null) {
- throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
- "Failed to find data loader manager service");
- }
-
final DataLoaderParams params = this.params.dataLoaderParams;
final boolean manualStartAndDestroy = !isIncrementalInstallation();
final boolean systemDataLoader = isSystemDataLoaderInstallation();
@@ -3793,20 +3786,13 @@
return;
}
try {
- IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
- if (dataLoader == null) {
- mDataLoaderFinished = true;
- dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
- "Failure to obtain data loader");
- return;
- }
-
switch (status) {
case IDataLoaderStatusListener.DATA_LOADER_BOUND: {
if (manualStartAndDestroy) {
FileSystemControlParcel control = new FileSystemControlParcel();
control.callback = new FileSystemConnector(addedFiles);
- dataLoader.create(dataLoaderId, params.getData(), control, this);
+ getDataLoader(dataLoaderId).create(dataLoaderId, params.getData(),
+ control, this);
}
break;
@@ -3815,12 +3801,12 @@
if (manualStartAndDestroy) {
// IncrementalFileStorages will call start after all files are
// created in IncFS.
- dataLoader.start(dataLoaderId);
+ getDataLoader(dataLoaderId).start(dataLoaderId);
}
break;
}
case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
- dataLoader.prepareImage(
+ getDataLoader(dataLoaderId).prepareImage(
dataLoaderId,
addedFiles.toArray(
new InstallationFileParcel[addedFiles.size()]),
@@ -3836,7 +3822,7 @@
dispatchSessionSealed();
}
if (manualStartAndDestroy) {
- dataLoader.destroy(dataLoaderId);
+ getDataLoader(dataLoaderId).destroy(dataLoaderId);
}
break;
}
@@ -3845,7 +3831,7 @@
dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to prepare image.");
if (manualStartAndDestroy) {
- dataLoader.destroy(dataLoaderId);
+ getDataLoader(dataLoaderId).destroy(dataLoaderId);
}
break;
}
@@ -3860,11 +3846,12 @@
break;
}
case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
- mDataLoaderFinished = true;
- dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"DataLoader reported unrecoverable failure.");
- break;
}
+ } catch (PackageManagerException e) {
+ mDataLoaderFinished = true;
+ dispatchSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
} catch (RemoteException e) {
// In case of streaming failure we don't want to fail or commit the session.
// Just return from this method and allow caller to commit again.
@@ -3939,7 +3926,7 @@
}
final long bindDelayMs = 0;
- if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), bindDelayMs,
+ if (!getDataLoaderManager().bindToDataLoader(sessionId, params.getData(), bindDelayMs,
statusListener)) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to initialize data loader");
@@ -3948,6 +3935,24 @@
return false;
}
+ private DataLoaderManager getDataLoaderManager() throws PackageManagerException {
+ DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+ if (dataLoaderManager == null) {
+ throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ "Failed to find data loader manager service");
+ }
+ return dataLoaderManager;
+ }
+
+ private IDataLoader getDataLoader(int dataLoaderId) throws PackageManagerException {
+ IDataLoader dataLoader = getDataLoaderManager().getDataLoader(dataLoaderId);
+ if (dataLoader == null) {
+ throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ "Failure to obtain data loader");
+ }
+ return dataLoader;
+ }
+
private void dispatchSessionValidationFailure(int error, String detailMessage) {
mHandler.obtainMessage(MSG_SESSION_VALIDATION_FAILURE, error, -1,
detailMessage).sendToTarget();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 20ca949..01c89b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1926,20 +1926,13 @@
int flags, int userId);
@NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
int flags, int userId, int callingUid, boolean includeInstantApps);
- @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
- String resolvedType, int flags, int userId, int callingUid,
- String instantAppPkgName);
@NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName);
- @Nullable ComponentName findInstallFailureActivity(String packageName, int filterCallingUid,
- int userId);
ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId);
- ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
- int filterCallingUid, int userId);
AndroidPackage getPackage(String packageName);
AndroidPackage getPackage(int uid);
ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
@@ -1947,11 +1940,6 @@
ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId);
- ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
- int filterCallingUid, int userId);
- ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(Intent intent,
- int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
- int userId, boolean debug);
ComponentName getDefaultHomeActivity(int userId);
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
@@ -1962,57 +1950,25 @@
List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent);
- List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
- String instantAppPkgName, @UserIdInt int userId, int filterCallingUid);
- List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
- int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
- int userId);
- List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos, int userId);
- List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
- String resolvedType, int flags, int userId, boolean resolveForStart,
- boolean isRequesterInstantApp);
PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
int filterCallingUid, int userId);
- PackageInfo getPackageInfoInternalBody(String packageName, long versionCode, int flags,
- int filterCallingUid, int userId);
PackageSetting getPackageSetting(String packageName);
PackageSetting getPackageSettingInternal(String packageName, int callingUid);
ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId);
- ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
- int callingUid);
- ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,
- String resolvedType, int flags, int sourceUserId);
ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId);
- ResolveInfo queryCrossProfileIntents(List<CrossProfileIntentFilter> matchingFilters,
- Intent intent, String resolvedType, int flags, int sourceUserId,
- boolean matchInCurrentProfile);
- ResolveInfo querySkipCurrentProfileIntents(List<CrossProfileIntentFilter> matchingFilters,
- Intent intent, String resolvedType, int flags, int sourceUserId);
ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
- ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
- int callingUid);
SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version);
String getInstantAppPackageName(int callingUid);
String resolveExternalPackageNameLPr(AndroidPackage pkg);
- String resolveInternalPackageNameInternalLocked(String packageName, long versionCode,
- int callingUid);
String resolveInternalPackageNameLPr(String packageName, long versionCode);
String[] getPackagesForUid(int uid);
- String[] getPackagesForUidInternal(int uid, int callingUid);
- String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
- boolean isCallerInstantApp);
UserInfo getProfileParent(int userId);
- boolean areWebInstantAppsDisabled(int userId);
boolean canViewInstantApps(int callingUid, int userId);
boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags);
- boolean hasCrossUserPermission(int callingUid, int callingUserId, int userId,
- boolean requireFullPermission, boolean requirePermissionWhenSameUser);
- boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos);
- boolean hasPermission(String permission);
boolean isCallerSameApp(String packageName, int uid);
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@@ -2021,27 +1977,15 @@
String resolvedType, int flags);
boolean isInstantApp(String packageName, int userId);
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
- boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid);
- boolean isInstantAppResolutionAllowed(Intent intent, List<ResolveInfo> resolvedActivities,
- int userId, boolean skipPackageCheck, int flags);
- boolean isInstantAppResolutionAllowedBody(Intent intent,
- List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
- int flags);
- boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
- String resolvedType, int flags);
- boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId);
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
- boolean isUserEnabled(int userId);
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId);
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
int userId);
boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
int userId);
- int bestDomainVerificationStatus(int status1, int status2);
int checkUidPermission(String permName, int uid);
int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
- int updateFlags(int flags, int userId);
int updateFlagsForApplication(int flags, int userId);
int updateFlagsForComponent(int flags, int userId);
int updateFlagsForPackage(int flags, int userId);
@@ -2348,7 +2292,7 @@
userId, callingUid, instantAppPkgName);
}
- public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+ protected @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
String instantAppPkgName) {
// reader
@@ -2486,7 +2430,7 @@
* creating an activity with an intent filter that handles the action
* {@link Intent#ACTION_INSTALL_FAILURE}.
*/
- public @Nullable ComponentName findInstallFailureActivity(
+ private @Nullable ComponentName findInstallFailureActivity(
String packageName, int filterCallingUid, int userId) {
final Intent failureActivityIntent = new Intent(Intent.ACTION_INSTALL_FAILURE);
failureActivityIntent.setPackage(packageName);
@@ -2532,7 +2476,7 @@
return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
}
- public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+ protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
int filterCallingUid, int userId) {
ParsedActivity a = mComponentResolver.getActivity(component);
@@ -2624,7 +2568,7 @@
return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
}
- public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+ protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
int filterCallingUid, int userId) {
// writer
// Normalize package name to handle renamed packages and static libs
@@ -2678,7 +2622,7 @@
return null;
}
- public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+ protected ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
Intent intent, int matchFlags, List<ResolveInfo> candidates,
CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
final ArrayList<ResolveInfo> result = new ArrayList<>();
@@ -3017,7 +2961,7 @@
return resolveInfos;
}
- public List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
+ private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) {
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
final ResolveInfo info = resolveInfos.get(i);
@@ -3105,7 +3049,8 @@
*
* @return filtered list
*/
- public List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos, int userId) {
+ private List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos,
+ int userId) {
if (userId == UserHandle.USER_SYSTEM) {
return resolveInfos;
}
@@ -3118,7 +3063,7 @@
return resolveInfos;
}
- public List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result,
+ private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result,
Intent intent,
String resolvedType, int flags, int userId, boolean resolveForStart,
boolean isRequesterInstantApp) {
@@ -3314,7 +3259,7 @@
userId);
}
- public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+ protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
// reader
// Normalize package name to handle renamed packages and static libs
@@ -3398,7 +3343,7 @@
return getInstalledPackagesBody(flags, userId, callingUid);
}
- public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+ protected ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
int callingUid) {
// writer
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
@@ -3473,7 +3418,7 @@
* will forward the intent to the filter's target user.
* Otherwise, returns null.
*/
- public ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
+ private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
Intent intent,
String resolvedType, int flags, int sourceUserId) {
int targetUserId = filter.getTargetUserId();
@@ -3528,7 +3473,7 @@
}
// Return matching ResolveInfo in target user if any.
- public ResolveInfo queryCrossProfileIntents(
+ private ResolveInfo queryCrossProfileIntents(
List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
int flags, int sourceUserId, boolean matchInCurrentProfile) {
if (matchingFilters != null) {
@@ -3558,7 +3503,7 @@
return null;
}
- public ResolveInfo querySkipCurrentProfileIntents(
+ private ResolveInfo querySkipCurrentProfileIntents(
List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
int flags, int sourceUserId) {
if (matchingFilters != null) {
@@ -3589,7 +3534,7 @@
return getServiceInfoBody(component, flags, userId, callingUid);
}
- public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+ protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
int callingUid) {
ParsedService s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3656,7 +3601,7 @@
return pkg.getPackageName();
}
- public String resolveInternalPackageNameInternalLocked(
+ private String resolveInternalPackageNameInternalLocked(
String packageName, long versionCode, int callingUid) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
@@ -3748,14 +3693,14 @@
return getPackagesForUidInternal(uid, Binder.getCallingUid());
}
- public String[] getPackagesForUidInternal(int uid, int callingUid) {
+ private String[] getPackagesForUidInternal(int uid, int callingUid) {
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
}
- public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+ protected String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
boolean isCallerInstantApp) {
// reader
final Object obj = mSettings.getSettingLPr(appId);
@@ -3797,7 +3742,7 @@
/**
* Returns whether or not instant apps have been disabled remotely.
*/
- public boolean areWebInstantAppsDisabled(int userId) {
+ private boolean areWebInstantAppsDisabled(int userId) {
return mWebInstantAppsDisabled.get(userId);
}
@@ -3894,7 +3839,7 @@
return true;
}
- public boolean hasCrossUserPermission(
+ private boolean hasCrossUserPermission(
int callingUid, int callingUserId, int userId, boolean requireFullPermission,
boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
@@ -3914,11 +3859,11 @@
* @param resolveInfos list of resolve infos in descending priority order
* @return if the list contains a resolve info with non-negative priority
*/
- public boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos) {
+ private boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos) {
return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
}
- public boolean hasPermission(String permission) {
+ private boolean hasPermission(String permission) {
return mContext.checkCallingOrSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}
@@ -4012,7 +3957,7 @@
return isInstantAppInternalBody(packageName, userId, callingUid);
}
- public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+ protected boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
int callingUid) {
if (Process.isIsolated(callingUid)) {
callingUid = getIsolatedOwner(callingUid);
@@ -4030,7 +3975,7 @@
return false;
}
- public boolean isInstantAppResolutionAllowed(
+ private boolean isInstantAppResolutionAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck, int flags) {
if (mInstantAppResolverConnection == null) {
@@ -4070,7 +4015,7 @@
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
- public boolean isInstantAppResolutionAllowedBody(
+ protected boolean isInstantAppResolutionAllowedBody(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck, int flags) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
@@ -4103,7 +4048,7 @@
return true;
}
- public boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+ private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
String resolvedType, int flags) {
PersistentPreferredIntentResolver ppir =
mSettings.getPersistentPreferredActivities(userId);
@@ -4121,7 +4066,7 @@
return false;
}
- public boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
+ private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
if (!mInjector.getLocalService(ActivityTaskManagerInternal.class)
.isCallerRecents(callingUid)) {
return false;
@@ -4147,7 +4092,7 @@
}
}
- public boolean isUserEnabled(int userId) {
+ private boolean isUserEnabled(int userId) {
final long callingId = Binder.clearCallingIdentity();
try {
UserInfo userInfo = mUserManager.getUserInfo(userId);
@@ -4247,7 +4192,7 @@
* Verification statuses are ordered from the worse to the best, except for
* INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
*/
- public int bestDomainVerificationStatus(int status1, int status2) {
+ private int bestDomainVerificationStatus(int status1, int status2) {
if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
return status2;
}
@@ -4287,7 +4232,7 @@
/**
* Update given flags based on encryption status of current user.
*/
- public int updateFlags(int flags, int userId) {
+ private int updateFlags(int flags, int userId) {
if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
// Caller expressed an explicit opinion about what encryption
@@ -7892,12 +7837,6 @@
flags, filterCallingUid, userId);
}
- private PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
- int flags, int filterCallingUid, int userId) {
- return liveComputer().getPackageInfoInternalBody(packageName, versionCode,
- flags, filterCallingUid, userId);
- }
-
private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
return liveComputer().isComponentVisibleToInstantApp(component);
}
@@ -8084,12 +8023,6 @@
filterCallingUid, userId);
}
- private ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
- int filterCallingUid, int userId) {
- return liveComputer().getApplicationInfoInternalBody(packageName, flags,
- filterCallingUid, userId);
- }
-
@GuardedBy("mLock")
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
@@ -8317,13 +8250,6 @@
}
/**
- * Update given flags based on encryption status of current user.
- */
- private int updateFlags(int flags, int userId) {
- return liveComputer().updateFlags(flags, userId);
- }
-
- /**
* Update given flags when being used to request {@link PackageInfo}.
*/
private int updateFlagsForPackage(int flags, int userId) {
@@ -8417,16 +8343,6 @@
filterCallingUid, userId);
}
- private ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
- int filterCallingUid, int userId) {
- return liveComputer().getActivityInfoInternalBody(component, flags,
- filterCallingUid, userId);
- }
-
- private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
- return liveComputer().isRecentsAccessingChildProfiles(callingUid, targetUserId);
- }
-
@Override
public boolean activitySupportsIntent(ComponentName component, Intent intent,
String resolvedType) {
@@ -8692,12 +8608,6 @@
return snapshotComputer().getServiceInfo(component, flags, userId);
}
- private ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
- int callingUid) {
- return liveComputer().getServiceInfoBody(component, flags, userId,
- callingUid);
- }
-
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
@@ -9245,16 +9155,6 @@
return snapshotComputer().getPackagesForUid(uid);
}
- private String[] getPackagesForUidInternal(int uid, int callingUid) {
- return liveComputer().getPackagesForUidInternal(uid, callingUid);
- }
-
- private String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
- boolean isCallerInstantApp) {
- return liveComputer().getPackagesForUidInternalBody(callingUid, userId, appId,
- isCallerInstantApp);
- }
-
@Override
public String getNameForUid(int uid) {
final int callingUid = Binder.getCallingUid();
@@ -9558,31 +9458,6 @@
intent, resolvedType, flags, query, 0, false, false, false, userId);
}
- /**
- * Returns whether or not instant apps have been disabled remotely.
- */
- private boolean areWebInstantAppsDisabled(int userId) {
- return liveComputer().areWebInstantAppsDisabled(userId);
- }
-
- private boolean isInstantAppResolutionAllowed(
- Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck, int flags) {
- return liveComputer().isInstantAppResolutionAllowed(
- intent, resolvedActivities, userId,
- skipPackageCheck, flags);
- }
-
- // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
- // Or if there's already an ephemeral app installed that handles the action
- private boolean isInstantAppResolutionAllowedBody(
- Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck, int flags) {
- return liveComputer().isInstantAppResolutionAllowedBody(
- intent, resolvedActivities, userId,
- skipPackageCheck, flags);
- }
-
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
@Nullable String callingFeatureId, boolean isRequesterInstantApp,
@@ -9734,12 +9609,6 @@
resolvedType, flags);
}
- private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
- String resolvedType, int flags) {
- return liveComputer().isPersistentPreferredActivitySetByDpm(intent, userId,
- resolvedType, flags);
- }
-
@GuardedBy("mLock")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
@@ -10133,14 +10002,6 @@
instantAppPkgName);
}
- private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
- String resolvedType, int flags, int userId, boolean resolveForStart,
- boolean isRequesterInstantApp) {
- return liveComputer().maybeAddInstantAppInstaller(result, intent,
- resolvedType, flags, userId, resolveForStart,
- isRequesterInstantApp);
- }
-
private static class CrossProfileDomainInfo {
/* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
ResolveInfo resolveInfo;
@@ -10154,27 +10015,6 @@
}
/**
- * Verification statuses are ordered from the worse to the best, except for
- * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
- */
- private int bestDomainVerificationStatus(int status1, int status2) {
- return liveComputer().bestDomainVerificationStatus(status1, status2);
- }
-
- private boolean isUserEnabled(int userId) {
- return liveComputer().isUserEnabled(userId);
- }
-
- /**
- * Filter out activities with systemUserOnly flag set, when current user is not System.
- *
- * @return filtered list
- */
- private List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos, int userId) {
- return liveComputer().filterIfNotSystemUser(resolveInfos, userId);
- }
-
- /**
* Filters out ephemeral activities.
* <p>When resolving for an ephemeral app, only activities that 1) are defined in the
* ephemeral app or 2) marked with {@code visibleToEphemeral} are returned.
@@ -10193,72 +10033,6 @@
resolveForStart, userId, intent);
}
- /**
- * Returns the activity component that can handle install failures.
- * <p>By default, the instant application installer handles failures. However, an
- * application may want to handle failures on its own. Applications do this by
- * creating an activity with an intent filter that handles the action
- * {@link Intent#ACTION_INSTALL_FAILURE}.
- */
- private @Nullable ComponentName findInstallFailureActivity(
- String packageName, int filterCallingUid, int userId) {
- return liveComputer().findInstallFailureActivity(
- packageName, filterCallingUid, userId);
- }
-
- /**
- * @param resolveInfos list of resolve infos in descending priority order
- * @return if the list contains a resolve info with non-negative priority
- */
- private boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos) {
- return liveComputer().hasNonNegativePriority(resolveInfos);
- }
-
- private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
- int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
- int userId) {
- return liveComputer().filterCandidatesWithDomainPreferredActivitiesLPr(intent,
- matchFlags, candidates, xpDomainInfo,
- userId);
- }
-
- private ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
- Intent intent, int matchFlags, List<ResolveInfo> candidates,
- CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
- return liveComputer().filterCandidatesWithDomainPreferredActivitiesLPrBody(
- intent, matchFlags, candidates,
- xpDomainInfo, userId, debug);
- }
-
-
- private ResolveInfo querySkipCurrentProfileIntents(
- List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
- int flags, int sourceUserId) {
- return liveComputer().querySkipCurrentProfileIntents(
- matchingFilters, intent, resolvedType,
- flags, sourceUserId);
- }
-
- // Return matching ResolveInfo in target user if any.
- private ResolveInfo queryCrossProfileIntents(
- List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
- int flags, int sourceUserId, boolean matchInCurrentProfile) {
- return liveComputer().queryCrossProfileIntents(
- matchingFilters, intent, resolvedType,
- flags, sourceUserId, matchInCurrentProfile);
- }
-
- /**
- * If the filter's target user can handle the intent and is enabled: returns a ResolveInfo that
- * will forward the intent to the filter's target user.
- * Otherwise, returns null.
- */
- private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,
- String resolvedType, int flags, int sourceUserId) {
- return liveComputer().createForwardingResolveInfo(filter, intent,
- resolvedType, flags, sourceUserId);
- }
-
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
Intent[] specifics, String[] specificTypes, Intent intent,
@@ -10580,20 +10354,6 @@
includeInstantApps);
}
- private @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
- String resolvedType, int flags, int userId, int callingUid,
- String instantAppPkgName) {
- return liveComputer().queryIntentServicesInternalBody(intent,
- resolvedType, flags, userId, callingUid,
- instantAppPkgName);
- }
-
- private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
- String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) {
- return liveComputer().applyPostServiceResolutionFilter(resolveInfos,
- instantAppPkgName, userId, filterCallingUid);
- }
-
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
String resolvedType, int flags, int userId) {
@@ -10746,12 +10506,6 @@
return snapshotComputer().getInstalledPackages(flags, userId);
}
- private ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
- int callingUid) {
- return liveComputer().getInstalledPackagesBody(flags, userId,
- callingUid);
- }
-
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
@@ -10935,12 +10689,6 @@
callingUid);
}
- private boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
- int callingUid) {
- return liveComputer().isInstantAppInternalBody(packageName, userId,
- callingUid);
- }
-
@Override
public byte[] getInstantAppCookie(String packageName, int userId) {
if (HIDE_EPHEMERAL_APIS) {
@@ -11796,18 +11544,6 @@
requireFullPermission, checkShell, message);
}
- private boolean hasCrossUserPermission(
- int callingUid, int callingUserId, int userId, boolean requireFullPermission,
- boolean requirePermissionWhenSameUser) {
- return liveComputer().hasCrossUserPermission(
- callingUid, callingUserId, userId, requireFullPermission,
- requirePermissionWhenSameUser);
- }
-
- private boolean hasPermission(String permission) {
- return liveComputer().hasPermission(permission);
- }
-
private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
return liveComputer().isSameProfileGroup(callerUserId, userId);
}
@@ -20681,12 +20417,6 @@
return liveComputer().resolveInternalPackageNameLPr(packageName, versionCode);
}
- private String resolveInternalPackageNameInternalLocked(
- String packageName, long versionCode, int callingUid) {
- return liveComputer().resolveInternalPackageNameInternalLocked(
- packageName, versionCode, callingUid);
- }
-
boolean isCallerVerifier(int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
return mRequiredVerifierPackage != null &&
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index 1814a8e..a1e5153 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -33,9 +33,12 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Collection;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Callback data loader for PackageManagerShellCommand installations.
@@ -136,6 +139,12 @@
private final byte mMode;
private final String mData;
+ private final String mSalt;
+
+ private static AtomicLong sGlobalSalt = new AtomicLong((new SecureRandom()).nextLong());
+ private static Long nextGlobalSalt() {
+ return sGlobalSalt.incrementAndGet();
+ }
static Metadata forStdIn(String fileId) {
return new Metadata(STDIN, fileId);
@@ -144,7 +153,7 @@
/** @hide */
@VisibleForTesting
public static Metadata forLocalFile(String filePath) {
- return new Metadata(LOCAL_FILE, filePath);
+ return new Metadata(LOCAL_FILE, filePath, nextGlobalSalt().toString());
}
static Metadata forDataOnlyStreaming(String fileId) {
@@ -156,26 +165,71 @@
}
private Metadata(byte mode, String data) {
+ this(mode, data, null);
+ }
+
+ private Metadata(byte mode, String data, String salt) {
this.mMode = mode;
this.mData = (data == null) ? "" : data;
+ this.mSalt = salt;
}
static Metadata fromByteArray(byte[] bytes) throws IOException {
- if (bytes == null || bytes.length == 0) {
+ if (bytes == null || bytes.length < 5) {
return null;
}
- byte mode = bytes[0];
- String data = new String(bytes, 1, bytes.length - 1, StandardCharsets.UTF_8);
- return new Metadata(mode, data);
+ int offset = 0;
+ final byte mode = bytes[offset];
+ offset += 1;
+ final String data;
+ final String salt;
+ switch (mode) {
+ case LOCAL_FILE: {
+ int dataSize = ByteBuffer.wrap(bytes, offset, 4).order(
+ ByteOrder.LITTLE_ENDIAN).getInt();
+ offset += 4;
+ data = new String(bytes, offset, dataSize, StandardCharsets.UTF_8);
+ offset += dataSize;
+ salt = new String(bytes, offset, bytes.length - offset,
+ StandardCharsets.UTF_8);
+ break;
+ }
+ default:
+ data = new String(bytes, offset, bytes.length - offset,
+ StandardCharsets.UTF_8);
+ salt = null;
+ break;
+ }
+ return new Metadata(mode, data, salt);
}
/** @hide */
@VisibleForTesting
public byte[] toByteArray() {
- byte[] dataBytes = this.mData.getBytes(StandardCharsets.UTF_8);
- byte[] result = new byte[1 + dataBytes.length];
- result[0] = this.mMode;
- System.arraycopy(dataBytes, 0, result, 1, dataBytes.length);
+ final byte[] result;
+ final byte[] dataBytes = this.mData.getBytes(StandardCharsets.UTF_8);
+ switch (this.mMode) {
+ case LOCAL_FILE: {
+ int dataSize = dataBytes.length;
+ byte[] saltBytes = this.mSalt.getBytes(StandardCharsets.UTF_8);
+ result = new byte[1 + 4 + dataSize + saltBytes.length];
+ int offset = 0;
+ result[offset] = this.mMode;
+ offset += 1;
+ ByteBuffer.wrap(result, offset, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(
+ dataSize);
+ offset += 4;
+ System.arraycopy(dataBytes, 0, result, offset, dataSize);
+ offset += dataSize;
+ System.arraycopy(saltBytes, 0, result, offset, saltBytes.length);
+ break;
+ }
+ default:
+ result = new byte[1 + dataBytes.length];
+ result[0] = this.mMode;
+ System.arraycopy(dataBytes, 0, result, 1, dataBytes.length);
+ break;
+ }
return result;
}
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index bfddaea..bc65c3a 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.content.IntentFilter;
-import com.android.server.WatchedIntentResolver;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index 0aca6ee..fc7680b 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.content.IntentFilter;
-import com.android.server.WatchedIntentResolver;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f5a13d5..4bc87a2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4471,7 +4471,23 @@
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (pkg != null) {
pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion());
- pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion());
+ pw.print(" targetSdk="); pw.println(pkg.getTargetSdkVersion());
+
+ SparseIntArray minExtensionVersions = pkg.getMinExtensionVersions();
+
+ pw.print(prefix); pw.print(" minExtensionVersions=[");
+ if (minExtensionVersions != null) {
+ List<String> minExtVerStrings = new ArrayList<>();
+ int size = minExtensionVersions.size();
+ for (int index = 0; index < size; index++) {
+ int key = minExtensionVersions.keyAt(index);
+ int value = minExtensionVersions.valueAt(index);
+ minExtVerStrings.add(key + "=" + value);
+ }
+
+ pw.print(TextUtils.join(", ", minExtVerStrings));
+ }
+ pw.print("]");
}
pw.println();
if (pkg != null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 20f35f2..1e9d7e1 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1213,7 +1213,9 @@
final String pkg = shortcutInfo.getPackage();
final int userId = shortcutInfo.getUserId();
final String id = shortcutInfo.getId();
- getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
+ synchronized (mLock) {
+ getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
+ }
}
/** Return the last reset time. */
diff --git a/services/core/java/com/android/server/WatchedIntentResolver.java b/services/core/java/com/android/server/pm/WatchedIntentResolver.java
similarity index 82%
rename from services/core/java/com/android/server/WatchedIntentResolver.java
rename to services/core/java/com/android/server/pm/WatchedIntentResolver.java
index 0831c36..1c3d884 100644
--- a/services/core/java/com/android/server/WatchedIntentResolver.java
+++ b/services/core/java/com/android/server/pm/WatchedIntentResolver.java
@@ -14,18 +14,20 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.server.pm.WatchedIntentFilter;
+import com.android.server.IntentResolver;
import com.android.server.utils.Snappable;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
import com.android.server.utils.Watcher;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -34,7 +36,8 @@
* @param <R> The resolver type.
* {@hide}
*/
-public abstract class WatchedIntentResolver<F extends Watchable, R extends Object>
+public abstract class WatchedIntentResolver<F extends WatchedIntentFilter,
+ R extends WatchedIntentFilter>
extends IntentResolver<F, R>
implements Watchable, Snappable {
@@ -116,11 +119,21 @@
onChanged();
}
+ // Sorts a List of IntentFilter objects into descending priority order.
+ @SuppressWarnings("rawtypes")
+ private static final Comparator<WatchedIntentFilter> sResolvePrioritySorter =
+ new Comparator<>() {
+ public int compare(WatchedIntentFilter o1, WatchedIntentFilter o2) {
+ final int q1 = o1.getPriority();
+ final int q2 = o2.getPriority();
+ return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);
+ }
+ };
+
@Override
@SuppressWarnings("unchecked")
protected void sortResults(List<R> results) {
- super.sortResults(results);
- onChanged();
+ Collections.sort(results, sResolvePrioritySorter);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 61f51e3..0f67be7 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -444,6 +444,7 @@
componentInfo.directBootAware = mainComponent.isDirectBootAware();
componentInfo.enabled = mainComponent.isEnabled();
componentInfo.splitName = mainComponent.getSplitName();
+ componentInfo.attributionTags = mainComponent.getAttributionTags();
}
private static void assignStateFieldsForPackageItemInfo(
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 3a097a7..2cfbf26 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -44,6 +44,7 @@
import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
@@ -140,9 +141,10 @@
}
@Override
- public int checkOperation(int code, int uid, String packageName, boolean raw,
- QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
- return superImpl.apply(code, uid, packageName, raw);
+ public int checkOperation(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw,
+ QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
+ return superImpl.apply(code, uid, packageName, attributionTag, raw);
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c897c3e..c21f72e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1072,6 +1072,8 @@
private void powerLongPress(long eventTime) {
final int behavior = getResolvedLongPressOnPowerBehavior();
+ Slog.d(TAG, "powerLongPress: eventTime=" + eventTime
+ + " mLongPressOnPowerBehavior=" + mLongPressOnPowerBehavior);
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 457dc43..b1b537b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -304,6 +304,13 @@
mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion));
}
+ boolean isTelephonyTimeZoneDetectionSupported() {
+ enforceManageTimeZoneDetectorPermission();
+
+ return ServiceConfigAccessor.getInstance(mContext)
+ .isTelephonyTimeZoneDetectionFeatureSupported();
+ }
+
boolean isGeoTimeZoneDetectionSupported() {
enforceManageTimeZoneDetectorPermission();
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index 9899b448b..a4a46a3 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -18,6 +18,7 @@
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_ENABLED;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_TELEPHONY_DETECTION_SUPPORTED;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SERVICE_NAME;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_GEO_DETECTION_ENABLED;
@@ -61,6 +62,8 @@
return runIsAutoDetectionEnabled();
case SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED:
return runSetAutoDetectionEnabled();
+ case SHELL_COMMAND_IS_TELEPHONY_DETECTION_SUPPORTED:
+ return runIsTelephonyDetectionSupported();
case SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED:
return runIsGeoDetectionSupported();
case SHELL_COMMAND_IS_GEO_DETECTION_ENABLED:
@@ -89,6 +92,13 @@
return 0;
}
+ private int runIsTelephonyDetectionSupported() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enabled = mInterface.isTelephonyTimeZoneDetectionSupported();
+ pw.println(enabled);
+ return 0;
+ }
+
private int runIsGeoDetectionSupported() {
final PrintWriter pw = getOutPrintWriter();
boolean enabled = mInterface.isGeoTimeZoneDetectionSupported();
@@ -169,6 +179,9 @@
pw.printf(" Prints true/false according to the automatic time zone detection setting\n");
pw.printf(" %s true|false\n", SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED);
pw.printf(" Sets the automatic time zone detection setting.\n");
+ pw.printf(" %s\n", SHELL_COMMAND_IS_TELEPHONY_DETECTION_SUPPORTED);
+ pw.printf(" Prints true/false according to whether telephony time zone detection is"
+ + " supported on this device.\n");
pw.printf(" %s\n", SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED);
pw.printf(" Prints true/false according to whether geolocation time zone detection is"
+ " supported on this device.\n");
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index ae873e2..2ac50b6 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -66,7 +66,6 @@
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import com.android.server.utils.ManagedApplicationService.LogEvent;
@@ -86,6 +85,7 @@
import java.util.Collection;
import java.util.Date;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -856,12 +856,15 @@
// If user changed drop restrictions for the old user.
if (oldUserId != newUserId) {
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- false, mOverlayToken, null, oldUserId);
+ false, mOverlayToken, (Map<String, String[]>) null, oldUserId);
}
// Apply the restrictions for the current user based on vr state
- String[] exemptions = (exemptedPackage == null) ? new String[0] :
- new String[] { exemptedPackage };
+ ArrayMap<String, String[]> exemptions = null;
+ if (exemptedPackage != null) {
+ exemptions = new ArrayMap<>(1);
+ exemptions.put(exemptedPackage, new String[0]);
+ }
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
mVrModeEnabled, mOverlayToken, exemptions, newUserId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 667a4fa..b55e653 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6865,7 +6865,7 @@
}
// An activity in size compatibility mode may have override bounds which equals to its
// parent bounds, so the exact bounds should also be checked to allow IME window to attach
- // to the activity. See {@link DisplayContent#isImeAttachedToApp}.
+ // to the activity. See {@link DisplayContent#shouldImeAttachedToApp}.
final WindowContainer parent = getParent();
return parent == null || parent.getBounds().equals(overrideBounds);
}
@@ -7483,7 +7483,10 @@
if (mVisibleRequested) {
// It may toggle the UI for user to restart the size compatibility mode activity.
display.handleActivitySizeCompatModeIfNeeded(this);
- } else if (mCompatDisplayInsets != null) {
+ } else if (mCompatDisplayInsets != null && !visibleIgnoringKeyguard) {
+ // visibleIgnoringKeyguard is checked to avoid clearing mCompatDisplayInsets during
+ // displays change. Displays are turned off during the change so mVisibleRequested
+ // can be false.
// The override changes can only be obtained from display, because we don't have the
// difference of full configuration in each hierarchy.
final int displayChanges = display.getCurrentOverrideConfigurationChanges();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index d5a7619..c1b287f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -449,6 +449,19 @@
if (mRemoteAnimationController != null) {
mRemoteAnimationController.goodToGo(transit);
+ } else if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
+ && topOpeningAnim != null) {
+ if (mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+ && mService.getRecentsAnimationController() == null) {
+ final NavBarFadeAnimationController controller =
+ new NavBarFadeAnimationController(mDisplayContent);
+ // For remote animation case, the nav bar fades out and in is controlled by the
+ // remote side. For non-remote animation case, we play the fade out/in animation
+ // here. We play the nav bar fade-out animation when the app transition animation
+ // starts and play the fade-in animation sequentially once the fade-out is finished.
+ controller.fadeOutAndInSequentially(topOpeningAnim.getDurationHint(),
+ null /* fadeOutParent */, topOpeningApp.getSurfaceControl());
+ }
}
return redoLayout;
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 9855ea5..b24ab93 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -25,6 +25,9 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.server.wm.DisplayAreaProto.FEATURE_ID;
+import static com.android.server.wm.DisplayAreaProto.IS_ORGANIZED;
+import static com.android.server.wm.DisplayAreaProto.IS_ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA;
import static com.android.server.wm.DisplayAreaProto.NAME;
import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
@@ -273,6 +276,9 @@
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(NAME, mName);
proto.write(IS_TASK_DISPLAY_AREA, isTaskDisplayArea());
+ proto.write(IS_ROOT_DISPLAY_AREA, asRootDisplayArea() != null);
+ proto.write(FEATURE_ID, mFeatureId);
+ proto.write(IS_ORGANIZED, isOrganized());
proto.end(token);
}
@@ -515,7 +521,7 @@
return true;
}
- protected boolean isTaskDisplayArea() {
+ boolean isTaskDisplayArea() {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 91f75e5..52317d9 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1539,7 +1539,9 @@
// to cover the activity configuration change.
return false;
}
- if (r.mStartingData != null && r.mStartingData.hasImeSurface()) {
+ if ((r.mStartingData != null && r.mStartingData.hasImeSurface())
+ || (mInsetsStateController.getImeSourceProvider()
+ .getSource().getVisibleFrame() != null)) {
// Currently it is unknown that when will IME window be ready. Reject the case to
// avoid flickering by showing IME in inconsistent orientation.
return false;
@@ -3633,7 +3635,7 @@
return mImeInputTarget != null && !mImeInputTarget.inMultiWindowMode();
}
- boolean isImeAttachedToApp() {
+ boolean shouldImeAttachedToApp() {
return isImeControlledByApp()
&& mImeLayeringTarget != null
&& mImeLayeringTarget.mActivityRecord != null
@@ -3647,6 +3649,20 @@
}
/**
+ * Unlike {@link #shouldImeAttachedToApp()}, this method returns {@code @true} only when both
+ * the IME layering target is valid to attach the IME surface to the app, and the
+ * {@link #mInputMethodSurfaceParent} of the {@link ImeContainer} has actually attached to
+ * the app. (i.e. Even if {@link #shouldImeAttachedToApp()} returns {@code true}, calling this
+ * method will return {@code false} if the IME surface doesn't actually attach to the app.)
+ */
+ boolean isImeAttachedToApp() {
+ return shouldImeAttachedToApp()
+ && mInputMethodSurfaceParent != null
+ && mInputMethodSurfaceParent.isSameSurface(
+ mImeLayeringTarget.mActivityRecord.getSurfaceControl());
+ }
+
+ /**
* Finds the window which can host IME if IME target cannot host it.
* e.g. IME target cannot host IME when it's display has a parent display OR when display
* doesn't support IME/system decorations.
@@ -3774,7 +3790,7 @@
@VisibleForTesting
void attachAndShowImeScreenshotOnTarget() {
// No need to attach screenshot if the IME target not exists or screen is off.
- if (!isImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) {
+ if (!shouldImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) {
return;
}
@@ -3942,7 +3958,7 @@
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
- if (allowAttachToApp && isImeAttachedToApp()) {
+ if (allowAttachToApp && shouldImeAttachedToApp()) {
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 9d33a69..30151c3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -373,7 +373,6 @@
* when the navigation bar mode is changed.
*/
private boolean mShouldAttachNavBarToAppDuringTransition;
- private NavBarFadeAnimationController mNavBarFadeAnimationController;
// -------- PolicyHandler --------
private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
@@ -1088,7 +1087,6 @@
break;
case TYPE_NAVIGATION_BAR:
mNavigationBar = win;
- updateNavBarFadeController();
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
(displayFrames, windowState, inOutFrame) -> {
@@ -1234,7 +1232,6 @@
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
} else if (mNavigationBar == win || mNavigationBarAlt == win) {
mNavigationBar = null;
- updateNavBarFadeController();
mNavigationBarAlt = null;
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
} else if (mNotificationShade == win) {
@@ -2060,7 +2057,6 @@
res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition);
if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) {
mShouldAttachNavBarToAppDuringTransition = shouldAttach;
- updateNavBarFadeController();
}
}
@@ -2424,15 +2420,6 @@
} else {
// Restore visibilities and positions of system bars.
controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
- // To further allow the pull-down-from-the-top gesture to pull down the notification
- // shade as a consistent motion, we reroute the touch events here from the currently
- // touched window to the status bar after making it visible.
- if (swipeTarget == mStatusBar) {
- final boolean transferred = mStatusBar.transferTouch();
- if (!transferred) {
- Slog.i(TAG, "Could not transfer touch to the status bar");
- }
- }
}
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
@@ -3071,19 +3058,4 @@
boolean shouldAttachNavBarToAppDuringTransition() {
return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null;
}
-
- @Nullable NavBarFadeAnimationController getNavBarFadeAnimationController() {
- return mNavBarFadeAnimationController;
- }
-
- private void updateNavBarFadeController() {
- if (shouldAttachNavBarToAppDuringTransition()) {
- if (mNavBarFadeAnimationController == null) {
- mNavBarFadeAnimationController =
- new NavBarFadeAnimationController(mDisplayContent);
- }
- } else {
- mNavBarFadeAnimationController = null;
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index fd4bbd7..6340036 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
@@ -441,8 +444,9 @@
Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
}
+ final boolean containsAppExtras = containsApplicationExtras(mDataDescription);
mService.mRoot.forAllWindows(w -> {
- sendDragStartedLocked(w, touchX, touchY, mDataDescription, mData);
+ sendDragStartedLocked(w, touchX, touchY, containsAppExtras);
}, false /* traverseTopToBottom */);
}
@@ -455,9 +459,9 @@
* process, so it's safe for the caller to call recycle() on the event afterwards.
*/
private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
- ClipDescription desc, ClipData data) {
+ boolean containsAppExtras) {
final boolean interceptsGlobalDrag = targetInterceptsGlobalDrag(newWin);
- if (mDragInProgress && isValidDropTarget(newWin, interceptsGlobalDrag)) {
+ if (mDragInProgress && isValidDropTarget(newWin, containsAppExtras, interceptsGlobalDrag)) {
DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY,
interceptsGlobalDrag, false /* includeDragSurface */,
null /* dragAndDropPermission */);
@@ -476,10 +480,28 @@
}
}
- private boolean isValidDropTarget(WindowState targetWin, boolean interceptsGlobalDrag) {
+ /**
+ * Returns true if this is a drag of an application mime type.
+ */
+ private boolean containsApplicationExtras(ClipDescription desc) {
+ if (desc == null) {
+ return false;
+ }
+ return desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
+ || desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
+ || desc.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ }
+
+ private boolean isValidDropTarget(WindowState targetWin, boolean containsAppExtras,
+ boolean interceptsGlobalDrag) {
if (targetWin == null) {
return false;
}
+ if (!interceptsGlobalDrag && containsAppExtras) {
+ // App-drags can only go to windows that can intercept global drag, and not to normal
+ // app windows
+ return false;
+ }
if (!targetWin.isPotentialDragTarget(interceptsGlobalDrag)) {
return false;
}
@@ -522,7 +544,8 @@
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
}
- sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription, mData);
+ sendDragStartedLocked(newWin, mCurrentX, mCurrentY,
+ containsApplicationExtras(mDataDescription));
}
}
diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java
index 17d20ae..2f3ad40 100644
--- a/services/core/java/com/android/server/wm/FadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeAnimationController.java
@@ -37,7 +37,7 @@
*/
public class FadeAnimationController {
protected final Context mContext;
- private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
+ protected final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
public FadeAnimationController(DisplayContent displayContent) {
mContext = displayContent.mWmService.mContext;
@@ -69,17 +69,11 @@
return;
}
- final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
- if (animation == null) {
+ final FadeAnimationAdapter animationAdapter = createAdapter(show, windowToken);
+ if (animationAdapter == null) {
return;
}
- final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
- createAnimationSpec(animation);
-
- final FadeAnimationAdapter animationAdapter = new FadeAnimationAdapter(
- windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
-
// We deferred the end of the animation when hiding the token, so we need to end it now that
// it's shown again.
final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
@@ -92,7 +86,21 @@
show /* hidden */, animationType, finishedCallback);
}
- private LocalAnimationAdapter.AnimationSpec createAnimationSpec(@NonNull Animation animation) {
+ protected FadeAnimationAdapter createAdapter(boolean show, WindowToken windowToken) {
+ final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
+ if (animation == null) {
+ return null;
+ }
+
+ final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
+ createAnimationSpec(animation);
+
+ return new FadeAnimationAdapter(
+ windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
+ }
+
+ protected LocalAnimationAdapter.AnimationSpec createAnimationSpec(
+ @NonNull Animation animation) {
return new LocalAnimationAdapter.AnimationSpec() {
final Transformation mTransformation = new Transformation();
@@ -130,8 +138,8 @@
};
}
- private class FadeAnimationAdapter extends LocalAnimationAdapter {
- private final boolean mShow;
+ protected class FadeAnimationAdapter extends LocalAnimationAdapter {
+ protected final boolean mShow;
private final WindowToken mToken;
FadeAnimationAdapter(AnimationSpec windowAnimationSpec,
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index 30861eb..e50dc51 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -18,6 +18,7 @@
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import android.view.SurfaceControl;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
@@ -35,12 +36,17 @@
private static final Interpolator FADE_OUT_INTERPOLATOR =
new PathInterpolator(0.2f, 0f, 1f, 1f);
+ private DisplayContent mDisplayContent;
private final WindowState mNavigationBar;
private Animation mFadeInAnimation;
private Animation mFadeOutAnimation;
+ private SurfaceControl mFadeInParent;
+ private SurfaceControl mFadeOutParent;
+ private boolean mPlaySequentially = false;
public NavBarFadeAnimationController(DisplayContent displayContent) {
super(displayContent);
+ mDisplayContent = displayContent;
mNavigationBar = displayContent.getDisplayPolicy().getNavigationBar();
mFadeInAnimation = new AlphaAnimation(0f, 1f);
mFadeInAnimation.setDuration(FADE_IN_DURATION);
@@ -61,12 +67,103 @@
return mFadeOutAnimation;
}
+ @Override
+ protected FadeAnimationAdapter createAdapter(boolean show, WindowToken windowToken) {
+ final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
+ if (animation == null) {
+ return null;
+ }
+
+ final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
+ createAnimationSpec(animation);
+ return new NavFadeAnimationAdapter(
+ windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken,
+ show ? mFadeInParent : mFadeOutParent);
+ }
+
/**
* Run the fade-in/out animation for the navigation bar.
*
* @param show true for fade-in, otherwise for fade-out.
*/
public void fadeWindowToken(boolean show) {
- fadeWindowToken(show, mNavigationBar.mToken, ANIMATION_TYPE_APP_TRANSITION);
+ final FadeRotationAnimationController controller =
+ mDisplayContent.getFadeRotationAnimationController();
+ final Runnable fadeAnim = () -> fadeWindowToken(show, mNavigationBar.mToken,
+ ANIMATION_TYPE_APP_TRANSITION);
+ if (controller == null) {
+ fadeAnim.run();
+ } else if (!controller.isTargetToken(mNavigationBar.mToken)) {
+ // If fade rotation animation is running and the nav bar is not controlled by it:
+ // - For fade-in animation, defer the animation until fade rotation animation finishes.
+ // - For fade-out animation, just play the animation.
+ if (show) {
+ controller.setOnShowRunnable(fadeAnim);
+ } else {
+ fadeAnim.run();
+ }
+ } else {
+ // If fade rotation animation is running and controlling the nav bar, make sure we empty
+ // the mDeferredFinishCallbacks and defer the runnable until fade rotation animation
+ // finishes.
+ final Runnable runnable = mDeferredFinishCallbacks.remove(mNavigationBar.mToken);
+ if (runnable != null) {
+ controller.setOnShowRunnable(runnable);
+ }
+ }
+ }
+
+ void fadeOutAndInSequentially(long totalDuration, SurfaceControl fadeOutParent,
+ SurfaceControl fadeInParent) {
+ mPlaySequentially = true;
+ if (totalDuration > 0) {
+ // The animation duration of each animation varies so we set the fade-out duration to
+ // 1/3 of the total app transition duration and set the fade-in duration to 2/3 of it.
+ final long fadeInDuration = totalDuration * 2L / 3L;
+ mFadeOutAnimation.setDuration(totalDuration - fadeInDuration);
+ mFadeInAnimation.setDuration(fadeInDuration);
+ }
+ mFadeOutParent = fadeOutParent;
+ mFadeInParent = fadeInParent;
+ fadeWindowToken(false);
+ }
+
+ /**
+ * The animation adapter that is capable of playing fade-out and fade-in sequentially and
+ * reparenting the navigation bar to a specified SurfaceControl when fade animation starts.
+ */
+ protected class NavFadeAnimationAdapter extends FadeAnimationAdapter {
+ private SurfaceControl mParent;
+
+ NavFadeAnimationAdapter(AnimationSpec windowAnimationSpec,
+ SurfaceAnimationRunner surfaceAnimationRunner, boolean show,
+ WindowToken token, SurfaceControl parent) {
+ super(windowAnimationSpec, surfaceAnimationRunner, show, token);
+ mParent = parent;
+ }
+
+ @Override
+ public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
+ int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+ super.startAnimation(animationLeash, t, type, finishCallback);
+ if (mParent != null && mParent.isValid()) {
+ t.reparent(animationLeash, mParent);
+ // Place the nav bar on top of anything else (e.g. ime and starting window) in the
+ // parent.
+ t.setLayer(animationLeash, Integer.MAX_VALUE);
+ }
+ }
+
+ @Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ if (mPlaySequentially) {
+ if (!mShow) {
+ fadeWindowToken(true);
+ }
+ return false;
+ } else {
+ return super.shouldDeferAnimationFinish(endDeferFinishCallback);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index dec6460..b44a980 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -231,7 +231,8 @@
@Override
public void setFinishTaskTransaction(int taskId,
- PictureInPictureSurfaceTransaction finishTransaction) {
+ PictureInPictureSurfaceTransaction finishTransaction,
+ SurfaceControl overlay) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"setFinishTaskTransaction(%d): transaction=%s", taskId, finishTransaction);
final long token = Binder.clearCallingIdentity();
@@ -241,6 +242,7 @@
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (taskAdapter.mTask.mTaskId == taskId) {
taskAdapter.mFinishTransaction = finishTransaction;
+ taskAdapter.mFinishOverlay = overlay;
break;
}
}
@@ -289,12 +291,6 @@
}
}
if (!behindSystemBars) {
- // Make sure to update the correct IME parent in case that the IME parent
- // may be computed as display layer when re-layout window happens during
- // rotation but there is intermediate state that the bounds of task and
- // the IME target's activity is not the same during rotating.
- mDisplayContent.updateImeParent();
-
// Hiding IME if IME window is not attached to app.
// Since some windowing mode is not proper to snapshot Task with IME window
// while the app transitioning to the next task (e.g. split-screen mode)
@@ -518,7 +514,6 @@
void removeAnimation(TaskAnimationAdapter taskAdapter) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"removeAnimation(%d)", taskAdapter.mTask.mTaskId);
- taskAdapter.mTask.setCanAffectSystemUiFlags(true);
taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
taskAdapter);
mPendingAnimations.remove(taskAdapter);
@@ -633,6 +628,7 @@
return;
}
mNavigationBarAttachedToApp = true;
+ navWindow.mToken.cancelAnimation();
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
if (shouldTranslateNavBar) {
@@ -653,7 +649,8 @@
}
}
- private void restoreNavigationBarFromApp(boolean animate) {
+ @VisibleForTesting
+ void restoreNavigationBarFromApp(boolean animate) {
if (!mNavigationBarAttachedToApp) {
return;
}
@@ -676,23 +673,9 @@
t.setLayer(navToken.getSurfaceControl(), navToken.getLastLayer());
if (animate) {
- final NavBarFadeAnimationController navBarFadeAnimationController =
- mDisplayContent.getDisplayPolicy().getNavBarFadeAnimationController();
- final Runnable fadeInAnim = () -> {
- // Reparent the SurfaceControl of nav bar token back.
- t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
- // Run fade-in animation to show navigation bar back to bottom of the display.
- if (navBarFadeAnimationController != null) {
- navBarFadeAnimationController.fadeWindowToken(true);
- }
- };
- final FadeRotationAnimationController fadeRotationAnimationController =
- mDisplayContent.getFadeRotationAnimationController();
- if (fadeRotationAnimationController != null) {
- fadeRotationAnimationController.setOnShowRunnable(fadeInAnim);
- } else {
- fadeInAnim.run();
- }
+ final NavBarFadeAnimationController controller =
+ new NavBarFadeAnimationController(mDisplayContent);
+ controller.fadeWindowToken(true);
} else {
// Reparent the SurfaceControl of nav bar token back.
t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
@@ -1106,6 +1089,8 @@
private final Rect mLocalBounds = new Rect();
// The final surface transaction when animation is finished.
private PictureInPictureSurfaceTransaction mFinishTransaction;
+ // An overlay used to mask the content as an app goes into PIP
+ private SurfaceControl mFinishOverlay;
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
mTask = task;
@@ -1143,20 +1128,38 @@
void onCleanup() {
if (mFinishTransaction != null) {
final Transaction pendingTransaction = mTask.getPendingTransaction();
+
+ // Reparent the overlay
+ if (mFinishOverlay != null) {
+ pendingTransaction.reparent(mFinishOverlay, mTask.mSurfaceControl);
+ }
+
+ // Transfer the transform from the leash to the task
PictureInPictureSurfaceTransaction.apply(mFinishTransaction,
mTask.mSurfaceControl, pendingTransaction);
- mTask.setLastRecentsAnimationTransaction(mFinishTransaction);
+ mTask.setLastRecentsAnimationTransaction(mFinishTransaction, mFinishOverlay);
if (mDisplayContent.isFixedRotationLaunchingApp(mTargetActivityRecord)) {
// The transaction is needed for position when rotating the display.
mDisplayContent.mPinnedTaskController.setEnterPipTransaction(
mFinishTransaction);
}
mFinishTransaction = null;
+ mFinishOverlay = null;
pendingTransaction.apply();
+
+ // In the case where we are transferring the transform to the task in preparation
+ // for entering PIP, we disable the task being able to affect sysui flags otherwise
+ // it may cause a flash
+ if (mTask.getActivityType() != mTargetActivityType) {
+ mTask.setCanAffectSystemUiFlags(false);
+ }
} else if (!mTask.isAttached()) {
// Apply the task's pending transaction in case it is detached and its transaction
// is not reachable.
mTask.getPendingTransaction().apply();
+
+ // Reset whether this task can affect the sysui flags
+ mTask.setCanAffectSystemUiFlags(true);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 0879ddd..26dcf00 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2139,7 +2139,8 @@
// Move the last recents animation transaction from original task to the new one.
if (task.mLastRecentsAnimationTransaction != null) {
rootTask.setLastRecentsAnimationTransaction(
- task.mLastRecentsAnimationTransaction);
+ task.mLastRecentsAnimationTransaction,
+ task.mLastRecentsAnimationOverlay);
task.clearLastRecentsAnimationTransaction();
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2099565..e120754 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -482,6 +482,9 @@
// Do not forget to reset this after reparenting.
// TODO: remove this once the recents animation is moved to the Shell
PictureInPictureSurfaceTransaction mLastRecentsAnimationTransaction;
+ // The content overlay to be applied with mLastRecentsAnimationTransaction
+ // TODO: remove this once the recents animation is moved to the Shell
+ SurfaceControl mLastRecentsAnimationOverlay;
static final int LAYER_RANK_INVISIBLE = -1;
// Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
@@ -5383,6 +5386,10 @@
: WINDOWING_MODE_FULLSCREEN;
}
if (currentMode == WINDOWING_MODE_PINNED) {
+ // In the case that we've disabled affecting the SysUI flags as a part of seamlessly
+ // transferring the transform on the leash to the task, reset this state once we've
+ // actually entered pip
+ setCanAffectSystemUiFlags(true);
mRootWindowContainer.notifyActivityPipModeChanged(null);
}
if (likelyResolvedMode == WINDOWING_MODE_PINNED
@@ -7616,22 +7623,28 @@
reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM);
}
- void setLastRecentsAnimationTransaction(
- @NonNull PictureInPictureSurfaceTransaction transaction) {
+ void setLastRecentsAnimationTransaction(@NonNull PictureInPictureSurfaceTransaction transaction,
+ @Nullable SurfaceControl overlay) {
mLastRecentsAnimationTransaction = new PictureInPictureSurfaceTransaction(transaction);
+ mLastRecentsAnimationOverlay = overlay;
}
void clearLastRecentsAnimationTransaction() {
mLastRecentsAnimationTransaction = null;
+ mLastRecentsAnimationOverlay = null;
// reset also the transform introduced by mLastRecentsAnimationTransaction
getPendingTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]);
}
void maybeApplyLastRecentsAnimationTransaction() {
if (mLastRecentsAnimationTransaction != null) {
+ if (mLastRecentsAnimationOverlay != null) {
+ getPendingTransaction().reparent(mLastRecentsAnimationOverlay, mSurfaceControl);
+ }
PictureInPictureSurfaceTransaction.apply(mLastRecentsAnimationTransaction,
mSurfaceControl, getPendingTransaction());
mLastRecentsAnimationTransaction = null;
+ mLastRecentsAnimationOverlay = null;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index ccfdb8c..ae90a7d 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -2131,7 +2131,7 @@
}
@Override
- protected boolean isTaskDisplayArea() {
+ boolean isTaskDisplayArea() {
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index d49b6a0..9ffb2b1 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -425,7 +425,7 @@
final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
// Exclude IME window snapshot when IME isn't proper to attach to app.
final boolean excludeIme = imeWindow != null && imeWindow.getSurfaceControl() != null
- && !task.getDisplayContent().isImeAttachedToApp();
+ && !task.getDisplayContent().shouldImeAttachedToApp();
final WindowState navWindow =
task.getDisplayContent().getDisplayPolicy().getNavigationBar();
// If config_attachNavBarToAppDuringTransition is true, the nav bar will be reparent to the
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4eff18c..b93312a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2309,7 +2309,7 @@
// When the window configuration changed, we need to update the IME control target in
// case the app may lose the IME inets control when exiting from split-screen mode, or the
// IME parent may failed to attach to the app during rotating the screen.
- // See DisplayContent#isImeAttachedToApp, DisplayContent#isImeControlledByApp
+ // See DisplayContent#shouldImeAttachedToApp, DisplayContent#isImeControlledByApp
if (windowConfigChanged) {
getDisplayContent().updateImeControlTarget();
}
@@ -2409,18 +2409,22 @@
final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING;
if (startingWindow) {
ProtoLog.d(WM_DEBUG_STARTING_WINDOW, "Starting window removed %s", this);
- }
-
- if (startingWindow && StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
// Cancel the remove starting window animation on shell. The main window might changed
// during animating, checking for all windows would be safer.
if (mActivityRecord != null) {
- mActivityRecord.forAllWindows(w -> {
+ mActivityRecord.forAllWindowsUnchecked(w -> {
if (w.isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
w.cancelAnimation();
+ return true;
}
+ return false;
}, true);
}
+ } else if (mAttrs.type == TYPE_BASE_APPLICATION
+ && isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
+ // Cancel the remove starting window animation in case the binder dead before remove
+ // splash window.
+ cancelAnimation();
}
ProtoLog.v(WM_DEBUG_FOCUS, "Remove client=%x, surfaceController=%s Callers=%s",
@@ -2428,7 +2432,6 @@
mWinAnimator.mSurfaceController,
Debug.getCallers(5));
-
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index db52683..f439777 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -293,8 +293,8 @@
auto mode = read<int8_t>(metadata).value_or(STDIN);
if (mode == LOCAL_FILE) {
// local file and possibly signature
- return openLocalFile(env, jni, shellCommand, size,
- std::string(metadata.data, metadata.size));
+ auto dataSize = le32toh(read<int32_t>(metadata).value_or(0));
+ return openLocalFile(env, jni, shellCommand, size, std::string(metadata.data, dataSize));
}
if (!shellCommand) {
diff --git a/services/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp
index 646aabd..dd9a525 100644
--- a/services/core/jni/gnss/GnssMeasurementCallback.cpp
+++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp
@@ -54,6 +54,7 @@
jmethodID method_reportMeasurementData;
jmethodID method_satellitePvtBuilderBuild;
jmethodID method_satellitePvtBuilderCtor;
+jmethodID method_satellitePvtBuilderSetFlags;
jmethodID method_satellitePvtBuilderSetPositionEcef;
jmethodID method_satellitePvtBuilderSetVelocityEcef;
jmethodID method_satellitePvtBuilderSetClockInfo;
@@ -89,6 +90,9 @@
jclass satellitePvtBuilder = env->FindClass("android/location/SatellitePvt$Builder");
class_satellitePvtBuilder = (jclass)env->NewGlobalRef(satellitePvtBuilder);
method_satellitePvtBuilderCtor = env->GetMethodID(class_satellitePvtBuilder, "<init>", "()V");
+ method_satellitePvtBuilderSetFlags =
+ env->GetMethodID(class_satellitePvtBuilder, "setFlags",
+ "(I)Landroid/location/SatellitePvt$Builder;");
method_satellitePvtBuilderSetPositionEcef =
env->GetMethodID(class_satellitePvtBuilder, "setPositionEcef",
"(Landroid/location/SatellitePvt$PositionEcef;)"
@@ -313,22 +317,33 @@
if (measurement.flags & static_cast<uint32_t>(GnssMeasurement::HAS_SATELLITE_PVT)) {
const SatellitePvt& satellitePvt = measurement.satellitePvt;
- jobject positionEcef = env->NewObject(class_positionEcef, method_positionEcef,
- satellitePvt.satPosEcef.posXMeters,
- satellitePvt.satPosEcef.posYMeters,
- satellitePvt.satPosEcef.posZMeters,
- satellitePvt.satPosEcef.ureMeters);
- jobject velocityEcef =
- env->NewObject(class_velocityEcef, method_velocityEcef,
- satellitePvt.satVelEcef.velXMps, satellitePvt.satVelEcef.velYMps,
- satellitePvt.satVelEcef.velZMps, satellitePvt.satVelEcef.ureRateMps);
- jobject clockInfo = env->NewObject(class_clockInfo, method_clockInfo,
- satellitePvt.satClockInfo.satHardwareCodeBiasMeters,
- satellitePvt.satClockInfo.satTimeCorrectionMeters,
- satellitePvt.satClockInfo.satClkDriftMps);
+ uint16_t satFlags = static_cast<uint16_t>(satellitePvt.flags);
+ jobject positionEcef = nullptr;
+ jobject velocityEcef = nullptr;
+ jobject clockInfo = nullptr;
+
+ if (satFlags & SatellitePvt::HAS_POSITION_VELOCITY_CLOCK_INFO) {
+ positionEcef = env->NewObject(class_positionEcef, method_positionEcef,
+ satellitePvt.satPosEcef.posXMeters,
+ satellitePvt.satPosEcef.posYMeters,
+ satellitePvt.satPosEcef.posZMeters,
+ satellitePvt.satPosEcef.ureMeters);
+ velocityEcef =
+ env->NewObject(class_velocityEcef, method_velocityEcef,
+ satellitePvt.satVelEcef.velXMps, satellitePvt.satVelEcef.velYMps,
+ satellitePvt.satVelEcef.velZMps,
+ satellitePvt.satVelEcef.ureRateMps);
+ clockInfo = env->NewObject(class_clockInfo, method_clockInfo,
+ satellitePvt.satClockInfo.satHardwareCodeBiasMeters,
+ satellitePvt.satClockInfo.satTimeCorrectionMeters,
+ satellitePvt.satClockInfo.satClkDriftMps);
+ }
+
jobject satellitePvtBuilderObject =
env->NewObject(class_satellitePvtBuilder, method_satellitePvtBuilderCtor);
+ env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetFlags,
+ satellitePvt.flags);
env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetPositionEcef,
positionEcef);
env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetVelocityEcef,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 24699d9..8b816d0 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1174,7 +1174,8 @@
return -EINVAL;
}
if (auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); err) {
- LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
+ LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile [" << normPath
+ << "]: " << err;
return err;
}
if (params.size > 0) {
diff --git a/services/incremental/path.cpp b/services/incremental/path.cpp
index bf4e9616..73e00ae 100644
--- a/services/incremental/path.cpp
+++ b/services/incremental/path.cpp
@@ -171,7 +171,9 @@
}
details::CStrWrapper::CStrWrapper(std::string_view sv) {
- if (sv[sv.size()] == '\0') {
+ if (!sv.data()) {
+ mCstr = "";
+ } else if (sv[sv.size()] == '\0') {
mCstr = sv.data();
} else {
mCopy.emplace(sv);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1e4b248..7e718e5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1793,7 +1793,7 @@
t.traceEnd();
t.traceBegin("StartFontManagerService");
- mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+ mSystemServiceManager.startService(new FontManagerService.Lifecycle(context, safeMode));
t.traceEnd();
t.traceBegin("StartTextServicesManager");
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 5222511..d5e1cd6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -175,6 +175,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.LongConsumer;
@@ -2269,17 +2270,46 @@
() -> CompatChanges.isChangeEnabled(
eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
anyString(), any(UserHandle.class)));
- final long minWindow = 73;
+ final int minWindow = 73;
setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
+ final Random random = new Random(42);
+
// 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC.
for (int window = 1; window <= minWindow; window++) {
final PendingIntent pi = getNewMockPendingIntent();
+ final long futurity = random.nextInt(minWindow);
+
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, pi, 0, 0,
+ TEST_CALLING_UID, null);
+
+ final long minAllowed = (long) (futurity * 0.75); // This will always be <= minWindow.
+
+ assertEquals(1, mService.mAlarmStore.size());
+ final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
+ assertEquals(Math.max(minAllowed, window), a.windowLength);
+ }
+
+ for (int window = 1; window <= minWindow; window++) {
+ final PendingIntent pi = getNewMockPendingIntent();
+ final long futurity = 2 * minWindow + window; // implies (0.75 * futurity) > minWindow
+
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, pi, 0, 0,
+ TEST_CALLING_UID, null);
+
+ assertEquals(1, mService.mAlarmStore.size());
+ final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
+ assertEquals(minWindow, a.windowLength);
+ }
+
+ for (int i = 0; i < 20; i++) {
+ final long window = minWindow + random.nextInt(100);
+ final PendingIntent pi = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, window, pi, 0, 0, TEST_CALLING_UID, null);
assertEquals(1, mService.mAlarmStore.size());
final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
- assertEquals(minWindow, a.windowLength);
+ assertEquals(window, a.windowLength);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index 0e5c77c..b6bb394 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -193,8 +193,7 @@
public void testAppSearchLoggerHelper_testCopyNativeStats_search() {
int nativeLatencyMillis = 4;
int nativeNumTerms = 5;
- // TODO(b/185804196) query length needs to be added in the native stats.
- // int nativeQueryLength = 6;
+ int nativeQueryLength = 6;
int nativeNumNamespacesFiltered = 7;
int nativeNumSchemaTypesFiltered = 8;
int nativeRequestedPageSize = 9;
@@ -211,6 +210,7 @@
QueryStatsProto.newBuilder()
.setLatencyMs(nativeLatencyMillis)
.setNumTerms(nativeNumTerms)
+ .setQueryLength(nativeQueryLength)
.setNumNamespacesFiltered(nativeNumNamespacesFiltered)
.setNumSchemaTypesFiltered(nativeNumSchemaTypesFiltered)
.setRequestedPageSize(nativeRequestedPageSize)
@@ -235,7 +235,7 @@
SearchStats sStats = qBuilder.build();
assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms);
- // assertThat(sStats.getNativeQueryLength()).isEqualTo(nativeQueryLength);
+ assertThat(sStats.getQueryLength()).isEqualTo(nativeQueryLength);
assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered);
assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(nativeNumSchemaTypesFiltered);
assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
index 0fe3903..77e0135 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
@@ -110,7 +110,7 @@
.TOKENIZER_TYPE_PLAIN)
.build())
.addProperty(
- new AppSearchSchema.Int64PropertyConfig.Builder("pubDate")
+ new AppSearchSchema.LongPropertyConfig.Builder("pubDate")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index edb683b..a71e532 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -301,4 +301,28 @@
assertThat(sStats.getBackwardsIncompatibleTypeChangeCount())
.isEqualTo(backwardsIncompatibleTypeChangeCount);
}
+
+ @Test
+ public void testAppSearchStats_RemoveStats() {
+ int nativeLatencyMillis = 1;
+ @RemoveStats.DeleteType int deleteType = 2;
+ int documentDeletedCount = 3;
+
+ final RemoveStats rStats =
+ new RemoveStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDeleteType(deleteType)
+ .setDeletedDocumentCount(documentDeletedCount)
+ .build();
+
+ assertThat(rStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(rStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+ assertThat(rStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(rStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(rStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(rStats.getDeleteType()).isEqualTo(deleteType);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(documentDeletedCount);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index c862feb..f9b8373 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -947,6 +947,24 @@
assertThat(updated).isNotEqualTo(firstFontFamily);
}
+ @Test
+ public void deleteAllFiles() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, parser, fakeFsverityUtil,
+ mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+ dirForPreparation.loadFontFileMap();
+ dirForPreparation.update(Collections.singletonList(
+ newFontUpdateRequest("foo.ttf,1,foo", GOOD_SIGNATURE)));
+ assertThat(mConfigFile.exists()).isTrue();
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(1);
+
+ UpdatableFontDir.deleteAllFiles(mUpdatableFontFilesDir, mConfigFile);
+ assertThat(mConfigFile.exists()).isFalse();
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
+ }
+
private FontUpdateRequest newFontUpdateRequest(String content, String signature)
throws Exception {
File file = File.createTempFile("font", "ttf", mCacheDir);
diff --git a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
new file mode 100644
index 0000000..94ac9be
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+import static android.content.pm.ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.os.Build;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CompatibilityModeTest {
+
+ private boolean mCompatibilityModeEnabled;;
+ private AndroidPackage mMockAndroidPackage;
+ private PackageUserState mMockUserState;
+
+ @Before
+ public void setUp() {
+ mCompatibilityModeEnabled = PackageParser.sCompatibilityModeEnabled;
+ mMockAndroidPackage = mock(AndroidPackage.class);
+ mMockUserState = mock(PackageUserState.class);
+ mMockUserState.installed = true;
+ when(mMockUserState.isAvailable(anyInt())).thenReturn(true);
+ when(mMockUserState.getAllOverlayPaths()).thenReturn(null);
+ }
+
+ @After
+ public void tearDown() {
+ setGlobalCompatibilityMode(mCompatibilityModeEnabled);
+ }
+
+ // The following tests ensure that apps with target SDK of Cupcake always use compat mode.
+
+ @Test
+ public void testGlobalCompatModeEnabled_oldApp_supportAllScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_oldApp_supportSomeScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_oldApp_supportOnlyOneScreen_usesCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = FLAG_SUPPORTS_NORMAL_SCREENS;
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_oldApp_DoesntSupportAllScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, 0 /*flags*/);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_oldApp_supportAllScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_oldApp_supportSomeScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_oldApp_supportOnlyOneScreen_usesCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = FLAG_SUPPORTS_NORMAL_SCREENS;
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, flags);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_oldApp_doesntSupportAllScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.CUPCAKE, 0 /*flags*/);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ // The following tests ensure that apps with newer target SDK use compat mode as expected.
+
+ @Test
+ public void testGlobalCompatModeEnabled_newApp_supportAllScreens_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_newApp_supportSomeScreens_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_newApp_supportOnlyOneScreen_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final int flags = FLAG_SUPPORTS_NORMAL_SCREENS;
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeEnabled_newApp_doesntSupportAllScreens_usesCompatMode() {
+ setGlobalCompatibilityMode(true);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.DONUT, 0 /*flags*/);
+ assertThat(info.usesCompatibilityMode(), is(true));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_newApp_supportAllScreens_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_newApp_supportSomeScreens_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = (FLAG_SUPPORTS_LARGE_SCREENS
+ | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS
+ | FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_newApp_supportOnlyOneScreen_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final int flags = FLAG_SUPPORTS_NORMAL_SCREENS;
+ final ApplicationInfo info = generateMockApplicationInfo(Build.VERSION_CODES.DONUT, flags);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ @Test
+ public void testGlobalCompatModeDisabled_newApp_doesntSupportAllScreens_doesntUseCompatMode() {
+ setGlobalCompatibilityMode(false);
+ final ApplicationInfo info =
+ generateMockApplicationInfo(Build.VERSION_CODES.DONUT, 0 /*flags*/);
+ assertThat(info.usesCompatibilityMode(), is(false));
+ }
+
+ private ApplicationInfo generateMockApplicationInfo(int targetSdkVersion, int flags) {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = targetSdkVersion;
+ info.flags |= flags;
+ when(mMockAndroidPackage.toAppInfoWithoutState()).thenReturn(info);
+ return PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(mMockAndroidPackage,
+ 0 /*flags*/, mMockUserState, 0 /*userId*/, false /*assignUserFields*/);
+ }
+
+ private void setGlobalCompatibilityMode(boolean enabled) {
+ if (PackageParser.sCompatibilityModeEnabled == enabled) {
+ return;
+ }
+ PackageParser.setCompatibilityModeEnabled(enabled);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 57436f8..581ff54 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -509,7 +509,13 @@
.ignored("Checked separately in test")}
reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
requestedPermissions=${this.requestedPermissions?.contentToString()}
- requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
+ requestedPermissionsFlags=${
+ this.requestedPermissionsFlags?.map {
+ // Newer flags are stripped
+ it and (PackageInfo.REQUESTED_PERMISSION_REQUIRED
+ or PackageInfo.REQUESTED_PERMISSION_GRANTED)
+ }?.joinToString()
+ }
requiredAccountType=${this.requiredAccountType}
requiredForAllUsers=${this.requiredForAllUsers}
restrictedAccountType=${this.restrictedAccountType}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index de4698d..985b2d5 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -41,6 +41,7 @@
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"/>
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
@@ -75,6 +76,7 @@
<activity android:name="com.android.server.wm.ActivityOptionsTest$MainActivity"
android:turnScreenOn="true"
android:showWhenLocked="true" />
+ <activity android:name="com.android.server.wm.ScreenshotTests$ScreenshotActivity" />
</application>
<instrumentation
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 e09606e..ff4e5a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1904,7 +1904,7 @@
mDisplayContent.setImeInputTarget(appWin2);
mDisplayContent.computeImeTarget(true);
assertEquals(appWin2, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
- assertTrue(mDisplayContent.isImeAttachedToApp());
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
verify(mDisplayContent, atLeast(1)).attachAndShowImeScreenshotOnTarget();
verify(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(appWin1.getTask());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 1bddd7b..c47ffcf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -239,6 +239,35 @@
}
@Test
+ public void testInterceptGlobalDragDropIgnoresOtherWindows() {
+ WindowState globalInterceptWindow = createDropTargetWindow("Global drag test window", 0);
+ globalInterceptWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
+
+ // Necessary for now since DragState.sendDragStartedLocked() will recycle drag events
+ // immediately after dispatching, which is a problem when using mockito arguments captor
+ // because it returns and modifies the same drag event
+ TestIWindow iwindow = (TestIWindow) mWindow.mClient;
+ final ArrayList<DragEvent> dragEvents = new ArrayList<>();
+ iwindow.setDragEventJournal(dragEvents);
+ TestIWindow globalInterceptIWindow = (TestIWindow) globalInterceptWindow.mClient;
+ final ArrayList<DragEvent> globalInterceptWindowDragEvents = new ArrayList<>();
+ globalInterceptIWindow.setDragEventJournal(globalInterceptWindowDragEvents);
+
+ startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ,
+ createClipDataForActivity(null, mock(UserHandle.class)), () -> {
+ // Verify the start-drag event is sent for the intercept window but not the
+ // other window
+ assertTrue(dragEvents.isEmpty());
+ assertTrue(globalInterceptWindowDragEvents.get(0).getAction()
+ == ACTION_DRAG_STARTED);
+
+ mTarget.reportDropWindow(globalInterceptWindow.mInputChannelToken, 0, 0);
+ mTarget.handleMotionEvent(false, 0, 0);
+ mToken = globalInterceptWindow.mClient.asBinder();
+ });
+ }
+
+ @Test
public void testValidateAppActivityArguments() {
final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 23d57b8..3082a5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -516,20 +516,15 @@
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, false);
+ eq(mDefaultDisplay.mDisplayId), eq(false));
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
verify(transaction).setLayer(navToken.getSurfaceControl(), Integer.MAX_VALUE);
- final WindowContainer parent = navToken.getParent();
- final NavBarFadeAnimationController navBarFadeAnimationController =
- mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
-
mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+ verify(mController).restoreNavigationBarFromApp(eq(true));
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, true);
+ eq(mDefaultDisplay.mDisplayId), eq(true));
verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
- verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
- verify(navBarFadeAnimationController).fadeWindowToken(true);
}
@Test
@@ -543,20 +538,18 @@
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, false);
+ eq(mDefaultDisplay.mDisplayId), eq(false));
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
verify(transaction).setLayer(navToken.getSurfaceControl(), Integer.MAX_VALUE);
final WindowContainer parent = navToken.getParent();
- final NavBarFadeAnimationController navBarFadeAnimationController =
- mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+ verify(mController).restoreNavigationBarFromApp(eq(false));
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, true);
+ eq(mDefaultDisplay.mDisplayId), eq(true));
verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
- verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
}
@Test
@@ -571,39 +564,6 @@
}
@Test
- public void testFadeRotationAfterAttachAndBeforeRestore_notRestoreNavImmediately() {
- setupForShouldAttachNavBarDuringTransition();
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
- final ActivityRecord homeActivity = createHomeActivity();
- initializeRecentsAnimationController(mController, homeActivity);
-
- final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
- final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
-
- verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, false);
- verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
- verify(transaction).setLayer(navToken.getSurfaceControl(), Integer.MAX_VALUE);
-
- final WindowContainer parent = navToken.getParent();
- final NavBarFadeAnimationController navBarFadeAnimationController =
- mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
-
- FadeRotationAnimationController mockController =
- mock(FadeRotationAnimationController.class);
- doReturn(mockController).when(mDefaultDisplay).getFadeRotationAnimationController();
-
- mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
- verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, true);
- verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
- verify(mockController).setOnShowRunnable(any());
- verify(transaction, times(0)).reparent(navToken.getSurfaceControl(),
- parent.getSurfaceControl());
- verify(navBarFadeAnimationController, times(0)).fadeWindowToken(true);
- }
-
- @Test
public void testAttachNavBarInSplitScreenMode() {
setupForShouldAttachNavBarDuringTransition();
final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay,
@@ -619,20 +579,18 @@
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, false);
+ eq(mDefaultDisplay.mDisplayId), eq(false));
verify(navWindow).setSurfaceTranslationY(-secondary.getBounds().top);
verify(transaction).reparent(navToken.getSurfaceControl(), secondary.getSurfaceControl());
reset(navWindow);
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
final WindowContainer parent = navToken.getParent();
- final NavBarFadeAnimationController navBarFadeAnimationController =
- mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
- mDefaultDisplay.mDisplayId, true);
+ eq(mDefaultDisplay.mDisplayId), eq(true));
verify(navWindow).setSurfaceTranslationY(0);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
- verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
+ verify(mController).restoreNavigationBarFromApp(eq(false));
}
@Test
@@ -696,12 +654,8 @@
mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
mWm.setRecentsAnimationController(mController);
doReturn(navBar).when(mController).getNavigationBarWindow();
- final NavBarFadeAnimationController mockNavBarFadeAnimationController =
- mock(NavBarFadeAnimationController.class);
final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy());
doReturn(displayPolicy).when(mDefaultDisplay).getDisplayPolicy();
- doReturn(mockNavBarFadeAnimationController).when(displayPolicy)
- .getNavBarFadeAnimationController();
}
private static void initializeRecentsAnimationController(RecentsAnimationController controller,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
new file mode 100644
index 0000000..f542e29
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
+import android.view.PointerIcon;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Build/Install/Run:
+ * atest WmTests:ScreenshotTests
+ */
+@SmallTest
+@Presubmit
+public class ScreenshotTests {
+ private static final int BUFFER_WIDTH = 100;
+ private static final int BUFFER_HEIGHT = 100;
+
+ private final Instrumentation mInstrumentation = getInstrumentation();
+
+ @Rule
+ public ActivityTestRule<ScreenshotActivity> mActivityRule =
+ new ActivityTestRule<>(ScreenshotActivity.class);
+
+ private ScreenshotActivity mActivity;
+
+ @Before
+ public void setup() {
+ mActivity = mActivityRule.getActivity();
+ mInstrumentation.waitForIdleSync();
+ }
+
+ @Test
+ public void testScreenshotSecureLayers() {
+ SurfaceControl secureSC = new SurfaceControl.Builder()
+ .setName("SecureChildSurfaceControl")
+ .setBLASTLayer()
+ .setCallsite("makeSecureSurfaceControl")
+ .setSecure(true)
+ .build();
+
+ SurfaceControl.Transaction t = mActivity.addChildSc(secureSC);
+ mInstrumentation.waitForIdleSync();
+
+ GraphicBuffer buffer = GraphicBuffer.create(BUFFER_WIDTH, BUFFER_HEIGHT,
+ PixelFormat.RGBA_8888,
+ GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
+ | GraphicBuffer.USAGE_SW_WRITE_RARELY);
+
+ Canvas canvas = buffer.lockCanvas();
+ canvas.drawColor(Color.RED);
+ buffer.unlockCanvasAndPost(canvas);
+
+ t.show(secureSC)
+ .setBuffer(secureSC, buffer)
+ .setColorSpace(secureSC, ColorSpace.get(ColorSpace.Named.SRGB))
+ .apply(true);
+
+ SurfaceControl.LayerCaptureArgs args = new SurfaceControl.LayerCaptureArgs.Builder(secureSC)
+ .setCaptureSecureLayers(true)
+ .setChildrenOnly(false)
+ .build();
+ SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = SurfaceControl.captureLayers(args);
+ assertNotNull(hardwareBuffer);
+
+ Bitmap screenshot = hardwareBuffer.asBitmap();
+ assertNotNull(screenshot);
+
+ Bitmap swBitmap = screenshot.copy(Bitmap.Config.ARGB_8888, false);
+ screenshot.recycle();
+
+ int numMatchingPixels = PixelChecker.getNumMatchingPixels(swBitmap,
+ new PixelColor(PixelColor.RED));
+ long sizeOfBitmap = swBitmap.getWidth() * swBitmap.getHeight();
+ boolean success = numMatchingPixels == sizeOfBitmap;
+ swBitmap.recycle();
+
+ assertTrue(success);
+ }
+
+ public static class ScreenshotActivity extends Activity {
+ private static final long WAIT_TIMEOUT_S = 5;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().getDecorView().setPointerIcon(
+ PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL));
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ SurfaceControl.Transaction addChildSc(SurfaceControl surfaceControl) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ mHandler.post(() -> {
+ t.merge(getWindow().getRootSurfaceControl().buildReparentTransaction(
+ surfaceControl));
+ countDownLatch.countDown();
+ });
+
+ try {
+ countDownLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ }
+ return t;
+ }
+ }
+
+ public abstract static class PixelChecker {
+ static int getNumMatchingPixels(Bitmap bitmap, PixelColor pixelColor) {
+ int numMatchingPixels = 0;
+ for (int x = 0; x < bitmap.getWidth(); x++) {
+ for (int y = 0; y < bitmap.getHeight(); y++) {
+ int color = bitmap.getPixel(x, y);
+ if (matchesColor(pixelColor, color)) {
+ numMatchingPixels++;
+ }
+ }
+ }
+ return numMatchingPixels;
+ }
+
+ static boolean matchesColor(PixelColor expectedColor, int color) {
+ final float red = Color.red(color);
+ final float green = Color.green(color);
+ final float blue = Color.blue(color);
+ final float alpha = Color.alpha(color);
+
+ return alpha <= expectedColor.mMaxAlpha
+ && alpha >= expectedColor.mMinAlpha
+ && red <= expectedColor.mMaxRed
+ && red >= expectedColor.mMinRed
+ && green <= expectedColor.mMaxGreen
+ && green >= expectedColor.mMinGreen
+ && blue <= expectedColor.mMaxBlue
+ && blue >= expectedColor.mMinBlue;
+ }
+ }
+
+ public static class PixelColor {
+ public static final int BLACK = 0xFF000000;
+ public static final int RED = 0xFF0000FF;
+ public static final int GREEN = 0xFF00FF00;
+ public static final int BLUE = 0xFFFF0000;
+ public static final int YELLOW = 0xFF00FFFF;
+ public static final int MAGENTA = 0xFFFF00FF;
+ public static final int WHITE = 0xFFFFFFFF;
+
+ public static final int TRANSPARENT_RED = 0x7F0000FF;
+ public static final int TRANSPARENT_BLUE = 0x7FFF0000;
+ public static final int TRANSPARENT = 0x00000000;
+
+ // Default to black
+ public short mMinAlpha;
+ public short mMaxAlpha;
+ public short mMinRed;
+ public short mMaxRed;
+ public short mMinBlue;
+ public short mMaxBlue;
+ public short mMinGreen;
+ public short mMaxGreen;
+
+ public PixelColor(int color) {
+ short alpha = (short) ((color >> 24) & 0xFF);
+ short blue = (short) ((color >> 16) & 0xFF);
+ short green = (short) ((color >> 8) & 0xFF);
+ short red = (short) (color & 0xFF);
+
+ mMinAlpha = (short) getMinValue(alpha);
+ mMaxAlpha = (short) getMaxValue(alpha);
+ mMinRed = (short) getMinValue(red);
+ mMaxRed = (short) getMaxValue(red);
+ mMinBlue = (short) getMinValue(blue);
+ mMaxBlue = (short) getMaxValue(blue);
+ mMinGreen = (short) getMinValue(green);
+ mMaxGreen = (short) getMaxValue(green);
+ }
+
+ public PixelColor() {
+ this(BLACK);
+ }
+
+ private int getMinValue(short color) {
+ return Math.max(color - 4, 0);
+ }
+
+ private int getMaxValue(short color) {
+ return Math.min(color + 4, 0xFF);
+ }
+ }
+}
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 0925e12..7224a0e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -316,14 +316,14 @@
mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity));
// Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
- assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
+ assertFalse(mActivity.mDisplayContent.shouldImeAttachedToApp());
// Recompute the natural configuration without resolving size compat configuration.
mActivity.clearSizeCompatMode();
mActivity.onConfigurationChanged(mTask.getConfiguration());
// It should keep non-attachable because the resolved bounds will be computed according to
// the aspect ratio that won't match its parent bounds.
- assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
+ assertFalse(mActivity.mDisplayContent.shouldImeAttachedToApp());
// Activity max bounds should be sandboxed since it is letterboxed.
assertActivityMaxBoundsSandboxed();
}
@@ -358,7 +358,7 @@
// Because the aspect ratio of display doesn't exceed the max aspect ratio of activity.
// The activity should still fill its parent container and IME can attach to the activity.
assertTrue(mActivity.matchParentBounds());
- assertTrue(mActivity.mDisplayContent.isImeAttachedToApp());
+ assertTrue(mActivity.mDisplayContent.shouldImeAttachedToApp());
final Rect letterboxInnerBounds = new Rect();
mActivity.getLetterboxInnerBounds(letterboxInnerBounds);
@@ -521,6 +521,7 @@
mActivity.setState(STOPPED, "testSizeCompatMode");
mActivity.mVisibleRequested = false;
+ mActivity.visibleIgnoringKeyguard = false;
mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
// Simulate the display changes orientation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 81712c6..e9e2013 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -193,7 +193,7 @@
Task task = mAppWindow.mActivityRecord.getTask();
spyOn(task);
spyOn(mDisplayContent);
- when(task.getDisplayContent().isImeAttachedToApp()).thenReturn(false);
+ when(task.getDisplayContent().shouldImeAttachedToApp()).thenReturn(false);
// Intentionally set the SurfaceControl of input method window as null.
mDisplayContent.mInputMethodWindow.setSurfaceControl(null);
// Verify no NPE happens when calling createTaskSnapshot.
@@ -213,7 +213,7 @@
spyOn(task);
spyOn(mDisplayContent);
spyOn(mDisplayContent.mInputMethodWindow);
- when(task.getDisplayContent().isImeAttachedToApp()).thenReturn(true);
+ when(task.getDisplayContent().shouldImeAttachedToApp()).thenReturn(true);
// Intentionally set the IME window is in drawn state.
doReturn(true).when(mDisplayContent.mInputMethodWindow).isDrawn();
// Verify no NPE happens when calling createTaskSnapshot.
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index 5340245..677fe2f 100755
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -1550,6 +1550,11 @@
if (cur < TEXT_MIN) {
int length = parseValueLength(pduDataStream);
int startPos = pduDataStream.available();
+ if (length > startPos) {
+ Log.e(LOG_TAG, "parseContentType: Invalid length " + length
+ + " when available bytes are " + startPos);
+ return (PduContentTypes.contentTypes[0]).getBytes(); //"*/*"
+ }
pduDataStream.mark(1);
temp = pduDataStream.read();
assert(-1 != temp);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 33a9a96..1e9e0bd 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5549,7 +5549,7 @@
sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false);
sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY,
- new String[]{"ia", "default", "ims", "mms", "dun", "emergency"});
+ new String[]{"ia", "default", "mms", "dun"});
sDefaults.putBoolean(KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL, false);
sDefaults.putBoolean(KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL, false);
sDefaults.putBoolean(KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL, true);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4cd59a2..91ecbf0 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2352,6 +2352,12 @@
void setActiveDeviceToDeviceTransport(String transport);
/**
+ * Forces Device to Device communication to be enabled, even if the device config has it
+ * disabled.
+ */
+ void setDeviceToDeviceForceEnabled(boolean isForceEnabled);
+
+ /**
* Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
*/
boolean getCarrierSingleRegistrationEnabled(int subId);
diff --git a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
index fc1d839..014efc2 100644
--- a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
+++ b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
@@ -145,4 +145,21 @@
val received = mSender.getTimeline()
assertEquals(sent, received)
}
+
+ // If an invalid timeline is sent, the channel should get closed. This helps surface any
+ // app-originating bugs early, and forces the work-around to happen in the early stages of the
+ // event processing.
+ @Test
+ fun testSendAndReceiveInvalidTimeline() {
+ val sent = TestInputEventSender.Timeline(
+ inputEventId = 1, gpuCompletedTime = 3, presentTime = 2)
+ mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
+ val received = mSender.getTimeline()
+ assertEquals(null, received)
+ // Sender will no longer receive callbacks for this fd, even if receiver sends a valid
+ // timeline later
+ mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/)
+ val receivedSecondTimeline = mSender.getTimeline()
+ assertEquals(null, receivedSecondTimeline)
+ }
}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index 44f96c5..80b0dfe 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -247,7 +248,6 @@
assertThat(fontPathAfterReboot).isEqualTo(fontPath);
}
-
@Test
public void fdLeakTest() throws Exception {
long originalOpenFontCount =
@@ -273,6 +273,20 @@
}
}
+ @Test
+ public void fdLeakTest_withoutPermission() throws Exception {
+ Pattern patternEmojiVPlus1 =
+ Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
+ byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(
+ new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) {
+ assertThrows(SecurityException.class,
+ () -> updateFontFileWithoutPermission(fd, signature, 0));
+ }
+ List<String> openFiles = getOpenFiles("system_server");
+ assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0);
+ }
+
private static String insertCert(String certPath) throws Exception {
Pair<String, String> result;
try (InputStream is = new FileInputStream(certPath)) {
@@ -290,16 +304,21 @@
try (ParcelFileDescriptor fd =
ParcelFileDescriptor.open(new File(fontPath), MODE_READ_ONLY)) {
return SystemUtil.runWithShellPermissionIdentity(() -> {
- FontConfig fontConfig = mFontManager.getFontConfig();
- return mFontManager.updateFontFamily(
- new FontFamilyUpdateRequest.Builder()
- .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature))
- .build(),
- fontConfig.getConfigVersion());
+ int configVersion = mFontManager.getFontConfig().getConfigVersion();
+ return updateFontFileWithoutPermission(fd, signature, configVersion);
});
}
}
+ private int updateFontFileWithoutPermission(ParcelFileDescriptor fd, byte[] signature,
+ int configVersion) {
+ return mFontManager.updateFontFamily(
+ new FontFamilyUpdateRequest.Builder()
+ .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature))
+ .build(),
+ configVersion);
+ }
+
private String getFontPath(String psName) {
return SystemUtil.runWithShellPermissionIdentity(() -> {
FontConfig fontConfig = mFontManager.getFontConfig();
diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
index 00a0bff..19df3c7 100644
--- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -17,7 +17,6 @@
package android.net.vcn;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
-import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -26,12 +25,15 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
+import android.net.NetworkCapabilities;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.os.Parcel;
import org.junit.Test;
+import java.util.Arrays;
+
public class VcnTransportInfoTest {
private static final int SUB_ID = 1;
private static final int NETWORK_ID = 5;
@@ -56,6 +58,19 @@
}
@Test
+ public void testMakeCopyRedactForNetworkSettings() {
+ for (VcnTransportInfo info : Arrays.asList(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO)) {
+ assertEquals(
+ INVALID_SUBSCRIPTION_ID,
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getSubId());
+ assertNull(
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getWifiInfo());
+ }
+ }
+
+ @Test
public void testMakeCopyRedactForAccessFineLocation() {
assertEquals(
SUB_ID,
@@ -75,11 +90,20 @@
}
@Test
- public void testApplicableRedactions() {
- assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions());
- assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
- | REDACT_FOR_NETWORK_SETTINGS,
- WIFI_UNDERLYING_INFO.getApplicableRedactions());
+ public void testParcelUnparcel() {
+ verifyParcelingIsNull(CELL_UNDERLYING_INFO);
+ verifyParcelingIsNull(WIFI_UNDERLYING_INFO);
+ }
+
+ private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) {
+ VcnTransportInfo redacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(
+ NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS);
+
+ Parcel parcel = Parcel.obtain();
+ redacted.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+
+ assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel));
}
@Test