diff options
285 files changed, 9531 insertions, 6239 deletions
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt index 905000ac7c3d..cc79f6bf9682 100644 --- a/apex/appsearch/framework/api/current.txt +++ b/apex/appsearch/framework/api/current.txt @@ -2,6 +2,7 @@ package android.app.appsearch { public final class AppSearchBatchResult<KeyType, ValueType> { + method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getAll(); method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getFailures(); method @NonNull public java.util.Map<KeyType,ValueType> getSuccesses(); method public boolean isSuccess(); @@ -146,7 +147,7 @@ package android.app.appsearch { method public void put(@NonNull android.app.appsearch.PutDocumentsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>); method public void remove(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>); method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>); - method @NonNull public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>); + method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>); method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor); method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>); } @@ -358,7 +359,6 @@ package android.app.appsearch { method @NonNull public java.util.Set<java.lang.String> getIncompatibleTypes(); method @NonNull public java.util.Set<java.lang.String> getMigratedTypes(); method @NonNull public java.util.List<android.app.appsearch.SetSchemaResponse.MigrationFailure> getMigrationFailures(); - method public boolean isSuccess(); } public static class SetSchemaResponse.MigrationFailure { diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java index cd75b1456ba8..519c14f7bb40 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java @@ -100,7 +100,6 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl * Returns a {@link Map} of all keys mapped to the {@link AppSearchResult}s they produced. * * <p>The values of the {@link Map} will not be {@code null}. - * @hide */ @NonNull public Map<KeyType, AppSearchResult<ValueType>> getAll() { diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 73ca0ccab46d..3c02d108507c 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -497,7 +497,6 @@ public final class AppSearchSession implements Closeable { * @param callback Callback to receive errors. If the operation succeeds, the callback will be * invoked with {@code null}. */ - @NonNull public void reportUsage( @NonNull ReportUsageRequest request, @NonNull @CallbackExecutor Executor executor, diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java index 138eb23148af..72bb9f3d07c8 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java @@ -583,9 +583,9 @@ public class GenericDocument { * @param schemaType the {@link AppSearchSchema} type of the {@link GenericDocument}. The * provided {@code schemaType} must be defined using {@link AppSearchSession#setSchema} * prior to inserting a document of this {@code schemaType} into the AppSearch index - * using {@link AppSearchSession#put}. Otherwise, the document will - * be rejected by {@link AppSearchSession#put} with result code - * {@link AppSearchResult#RESULT_NOT_FOUND}. + * using {@link AppSearchSession#put}. Otherwise, the document will be rejected by + * {@link AppSearchSession#put} with result code {@link + * AppSearchResult#RESULT_NOT_FOUND}. */ @SuppressWarnings("unchecked") public Builder(@NonNull String uri, @NonNull String schemaType) { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java index 05b212880962..57700f89403e 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java @@ -28,9 +28,11 @@ import java.util.Collections; import java.util.List; /** - * Encapsulates a request to index a document into an {@link AppSearchSession} database. + * Encapsulates a request to index documents into an {@link AppSearchSession} database. * * <p>@see AppSearchSession#putDocuments + * + * @see AppSearchSession#put */ public final class PutDocumentsRequest { private final List<GenericDocument> mDocuments; @@ -39,7 +41,7 @@ public final class PutDocumentsRequest { mDocuments = documents; } - /** Returns the documents that are part of this request. */ + /** Returns a list of {@link GenericDocument} objects that are part of this request. */ @NonNull public List<GenericDocument> getGenericDocuments() { return Collections.unmodifiableList(mDocuments); @@ -54,14 +56,22 @@ public final class PutDocumentsRequest { private final List<GenericDocument> mDocuments = new ArrayList<>(); private boolean mBuilt = false; - /** Adds one or more {@link GenericDocument} objects to the request. */ + /** + * Adds one or more {@link GenericDocument} objects to the request. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public Builder addGenericDocuments(@NonNull GenericDocument... documents) { Preconditions.checkNotNull(documents); return addGenericDocuments(Arrays.asList(documents)); } - /** Adds a collection of {@link GenericDocument} objects to the request. */ + /** + * Adds a collection of {@link GenericDocument} objects to the request. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public Builder addGenericDocuments( @NonNull Collection<? extends GenericDocument> documents) { @@ -71,7 +81,11 @@ public final class PutDocumentsRequest { return this; } - /** Creates a new {@link PutDocumentsRequest} object. */ + /** + * Creates a new {@link PutDocumentsRequest} object. + * + * @throws IllegalStateException if the builder has already been used. + */ @NonNull public PutDocumentsRequest build() { Preconditions.checkState(!mBuilt, "Builder has already been used"); diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java index bc99d4f67d86..a146006f355c 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java @@ -79,12 +79,6 @@ public class SetSchemaResponse { return mBundle; } - /** TODO(b/177266929): Remove this deprecated method */ - //@Deprecated - public boolean isSuccess() { - return true; - } - /** * Returns a {@link List} of all failed {@link MigrationFailure}. * diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java index babcd25e3e26..7c92456bea49 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java @@ -218,9 +218,23 @@ public class VisibilityStore { * @throws AppSearchException AppSearchException on AppSearchImpl error. */ public void initialize() throws AppSearchException { - if (!mAppSearchImpl.hasSchemaTypeLocked(PACKAGE_NAME, DATABASE_NAME, VISIBILITY_TYPE) - || !mAppSearchImpl.hasSchemaTypeLocked( - PACKAGE_NAME, DATABASE_NAME, PACKAGE_ACCESSIBLE_TYPE)) { + List<AppSearchSchema> schemas = mAppSearchImpl.getSchema(PACKAGE_NAME, DATABASE_NAME); + boolean hasVisibilityType = false; + boolean hasPackageAccessibleType = false; + for (int i = 0; i < schemas.size(); i++) { + AppSearchSchema schema = schemas.get(i); + if (schema.getSchemaType().equals(VISIBILITY_TYPE)) { + hasVisibilityType = true; + } else if (schema.getSchemaType().equals(PACKAGE_ACCESSIBLE_TYPE)) { + hasPackageAccessibleType = true; + } + + if (hasVisibilityType && hasPackageAccessibleType) { + // Found both our types, can exit early. + break; + } + } + if (!hasVisibilityType || !hasPackageAccessibleType) { // Schema type doesn't exist yet. Add it. mAppSearchImpl.setSchema( PACKAGE_NAME, @@ -250,10 +264,11 @@ public class VisibilityStore { /*typePropertyPaths=*/ Collections.emptyMap()); // Update platform visibility settings - String[] schemas = + String[] notPlatformSurfaceableSchemas = document.getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY); - if (schemas != null) { - mNotPlatformSurfaceableMap.put(prefix, new ArraySet<>(Arrays.asList(schemas))); + if (notPlatformSurfaceableSchemas != null) { + mNotPlatformSurfaceableMap.put( + prefix, new ArraySet<>(Arrays.asList(notPlatformSurfaceableSchemas))); } // Update 3p package visibility settings @@ -333,7 +348,7 @@ public class VisibilityStore { schemasPackageAccessible.entrySet()) { for (int i = 0; i < entry.getValue().size(); i++) { GenericDocument packageAccessibleDocument = - new GenericDocument.Builder(/*uri=*/"", PACKAGE_ACCESSIBLE_TYPE) + new GenericDocument.Builder(/*uri=*/ "", PACKAGE_ACCESSIBLE_TYPE) .setNamespace(NAMESPACE) .setPropertyString( PACKAGE_NAME_PROPERTY, diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java new file mode 100644 index 000000000000..0f23d926648b --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage; + +import android.annotation.NonNull; +import android.app.appsearch.exceptions.AppSearchException; + +import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; + +/** + * An interface for implementing client-defined logging AppSearch operations stats. + * + * <p>Any implementation needs to provide general information on how to log all the stats types. + * (e.g. {@link CallStats}) + * + * <p>All implementations of this interface must be thread safe. + * + * @hide + */ +public interface AppSearchLogger { + /** Logs {@link CallStats} */ + void logStats(@NonNull CallStats stats) throws AppSearchException; + + /** Logs {@link PutDocumentStats} */ + void logStats(@NonNull PutDocumentStats stats) throws AppSearchException; + + // TODO(b/173532925) Add remaining logStats once we add all the stats. +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java index a501e99db1ef..a7f1cc4c793f 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java @@ -76,7 +76,7 @@ class AppSearchMigrationHelperImpl implements AppSearchMigrationHelper { int currentVersion = mCurrentVersionMap.get(schemaType); int finalVersion = mFinalVersionMap.get(schemaType); try (FileOutputStream outputStream = new FileOutputStream(mFile)) { - // TODO(b/177266929) change the output stream so that we can use it in platform + // TODO(b/151178558) change the output stream so that we can use it in platform CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); SearchResultPage searchResultPage = mAppSearchImpl.query( diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java new file mode 100644 index 000000000000..81a5067c9fa1 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java @@ -0,0 +1,200 @@ +/* + * 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 com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A class for setting basic information to log for all function calls. + * + * <p>This class can set which stats to log for both batch and non-batch {@link + * android.app.appsearch.AppSearchSession} calls. + * + * <p>Some function calls like {@link android.app.appsearch.AppSearchSession#setSchema} have their + * own detailed stats class {@link placeholder}. However, {@link CallStats} can still be used along + * with the detailed stats class for easy aggregation/analysis with other function calls. + * + * @hide + */ +public class CallStats { + @IntDef( + value = { + CALL_TYPE_UNKNOWN, + CALL_TYPE_INITIALIZE, + CALL_TYPE_SET_SCHEMA, + CALL_TYPE_PUT_DOCUMENTS, + CALL_TYPE_GET_DOCUMENTS, + CALL_TYPE_REMOVE_DOCUMENTS, + CALL_TYPE_PUT_DOCUMENT, + CALL_TYPE_GET_DOCUMENT, + CALL_TYPE_REMOVE_DOCUMENT, + CALL_TYPE_QUERY, + CALL_TYPE_OPTIMIZE, + CALL_TYPE_FLUSH, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallType {} + + public static final int CALL_TYPE_UNKNOWN = 0; + public static final int CALL_TYPE_INITIALIZE = 1; + public static final int CALL_TYPE_SET_SCHEMA = 2; + public static final int CALL_TYPE_PUT_DOCUMENTS = 3; + public static final int CALL_TYPE_GET_DOCUMENTS = 4; + public static final int CALL_TYPE_REMOVE_DOCUMENTS = 5; + public static final int CALL_TYPE_PUT_DOCUMENT = 6; + public static final int CALL_TYPE_GET_DOCUMENT = 7; + public static final int CALL_TYPE_REMOVE_DOCUMENT = 8; + public static final int CALL_TYPE_QUERY = 9; + public static final int CALL_TYPE_OPTIMIZE = 10; + public static final int CALL_TYPE_FLUSH = 11; + + @NonNull private final GeneralStats mGeneralStats; + @CallType private final int mCallType; + private final int mEstimatedBinderLatencyMillis; + private final int mNumOperationsSucceeded; + private final int mNumOperationsFailed; + + CallStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats); + mCallType = builder.mCallType; + mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis; + mNumOperationsSucceeded = builder.mNumOperationsSucceeded; + mNumOperationsFailed = builder.mNumOperationsFailed; + } + + /** Returns general information for the call. */ + @NonNull + public GeneralStats getGeneralStats() { + return mGeneralStats; + } + + /** Returns type of the call. */ + @CallType + public int getCallType() { + return mCallType; + } + + /** Returns estimated binder latency, in milliseconds */ + public int getEstimatedBinderLatencyMillis() { + return mEstimatedBinderLatencyMillis; + } + + /** + * Returns number of operations succeeded. + * + * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual successful put operations. In this case, how many documents are + * successfully indexed. + * + * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the + * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + public int getNumOperationsSucceeded() { + return mNumOperationsSucceeded; + } + + /** + * Returns number of operations failed. + * + * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual failed put operations. In this case, how many documents are failed to be + * indexed. + * + * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, the + * sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + public int getNumOperationsFailed() { + return mNumOperationsFailed; + } + + /** Builder for {@link CallStats}. */ + public static class Builder { + @NonNull final GeneralStats mGeneralStats; + @CallType int mCallType; + int mEstimatedBinderLatencyMillis; + int mNumOperationsSucceeded; + int mNumOperationsFailed; + + /** Builder takes {@link GeneralStats} to hold general stats. */ + public Builder(@NonNull GeneralStats generalStats) { + mGeneralStats = Preconditions.checkNotNull(generalStats); + } + + /** Sets type of the call. */ + @NonNull + public Builder setCallType(@CallType int callType) { + mCallType = callType; + return this; + } + + /** Sets estimated binder latency, in milliseconds. */ + @NonNull + public Builder setEstimatedBinderLatencyMillis(int estimatedBinderLatencyMillis) { + mEstimatedBinderLatencyMillis = estimatedBinderLatencyMillis; + return this; + } + + /** + * Sets number of operations succeeded. + * + * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual successful put operations. In this case, how many documents are + * successfully indexed. + * + * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, + * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + @NonNull + public Builder setNumOperationsSucceeded(int numOperationsSucceeded) { + mNumOperationsSucceeded = numOperationsSucceeded; + return this; + } + + /** + * Sets number of operations failed. + * + * <p>For example, for {@link android.app.appsearch.AppSearchSession#put}, it is the total + * number of individual failed put operations. In this case, how many documents are failed + * to be indexed. + * + * <p>For non-batch calls such as {@link android.app.appsearch.AppSearchSession#setSchema}, + * the sum of {@link CallStats#getNumOperationsSucceeded()} and {@link + * CallStats#getNumOperationsFailed()} is always 1 since there is only one operation. + */ + @NonNull + public Builder setNumOperationsFailed(int numOperationsFailed) { + mNumOperationsFailed = numOperationsFailed; + return this; + } + + /** Creates {@link CallStats} object from {@link Builder} instance. */ + @NonNull + public CallStats build() { + return new CallStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java new file mode 100644 index 000000000000..d2a45d5304f9 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java @@ -0,0 +1,122 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.NonNull; +import android.app.appsearch.AppSearchResult; + +import com.android.internal.util.Preconditions; + +/** + * A class for holding general logging information. + * + * <p>This class cannot be logged by {@link + * com.android.server.appsearch.external.localstorage.AppSearchLogger} directly. It is used for + * defining general logging information that is shared across different stats classes. + * + * @see PutDocumentStats + * @see CallStats + * @hide + */ +public final class GeneralStats { + /** Package name of the application. */ + @NonNull private final String mPackageName; + + /** Database name within AppSearch. */ + @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; + + GeneralStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mPackageName = Preconditions.checkNotNull(builder.mPackageName); + mDatabase = Preconditions.checkNotNull(builder.mDatabase); + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + } + + /** Returns package name. */ + @NonNull + public String getPackageName() { + return mPackageName; + } + + /** Returns database name. */ + @NonNull + public String getDatabase() { + return mDatabase; + } + + /** Returns result code from {@link AppSearchResult#getResultCode()} */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns total latency, in milliseconds. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Builder for {@link GeneralStats}. */ + public static class Builder { + @NonNull final String mPackageName; + @NonNull final String mDatabase; + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + + /** + * Constructor + * + * @param packageName name of the package logging stats + * @param dataBase name of the database logging stats + */ + public Builder(@NonNull String packageName, @NonNull String dataBase) { + mPackageName = Preconditions.checkNotNull(packageName); + mDatabase = Preconditions.checkNotNull(dataBase); + } + + /** Sets status code returned from {@link AppSearchResult#getResultCode()} */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency, in milliseconds. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** + * Creates a new {@link GeneralStats} object from the contents of this {@link Builder} + * instance. + */ + @NonNull + public GeneralStats build() { + return new GeneralStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java new file mode 100644 index 000000000000..b1b643b66859 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java @@ -0,0 +1,219 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.NonNull; + +import com.android.internal.util.Preconditions; + +/** + * A class for holding detailed stats to log for each individual document put by a {@link + * android.app.appsearch.AppSearchSession#put} call. + * + * @hide + */ +public final class PutDocumentStats { + /** {@link GeneralStats} holds the general stats. */ + @NonNull private final GeneralStats mGeneralStats; + + /** Time used to generate a document proto from a Bundle. */ + private final int mGenerateDocumentProtoLatencyMillis; + + /** Time used to rewrite types and namespaces in the document. */ + private final int mRewriteDocumentTypesLatencyMillis; + + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + + /** Time used to store the document. */ + private final int mNativeDocumentStoreLatencyMillis; + + /** Time used to index the document. It doesn't include the time to merge indices. */ + private final int mNativeIndexLatencyMillis; + + /** Time used to merge the indices. */ + private final int mNativeIndexMergeLatencyMillis; + + /** Document size in bytes. */ + private final int mNativeDocumentSizeBytes; + + /** Number of tokens added to the index. */ + private final int mNativeNumTokensIndexed; + + /** Number of tokens clipped for exceeding the max number. */ + private final int mNativeNumTokensClipped; + + PutDocumentStats(@NonNull Builder builder) { + Preconditions.checkNotNull(builder); + mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats); + mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis; + mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeDocumentStoreLatencyMillis = builder.mNativeDocumentStoreLatencyMillis; + mNativeIndexLatencyMillis = builder.mNativeIndexLatencyMillis; + mNativeIndexMergeLatencyMillis = builder.mNativeIndexMergeLatencyMillis; + mNativeDocumentSizeBytes = builder.mNativeDocumentSizeBytes; + mNativeNumTokensIndexed = builder.mNativeNumTokensIndexed; + mNativeNumTokensClipped = builder.mNativeNumTokensClipped; + } + + /** Returns the {@link GeneralStats} object attached to this instance. */ + @NonNull + public GeneralStats getGeneralStats() { + return mGeneralStats; + } + + /** Returns time spent on generating document proto, in milliseconds. */ + public int getGenerateDocumentProtoLatencyMillis() { + return mGenerateDocumentProtoLatencyMillis; + } + + /** Returns time spent on rewriting types and namespaces in document, in milliseconds. */ + public int getRewriteDocumentTypesLatencyMillis() { + return mRewriteDocumentTypesLatencyMillis; + } + + /** Returns time spent in native, in milliseconds. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns time spent on document store, in milliseconds. */ + public int getNativeDocumentStoreLatencyMillis() { + return mNativeDocumentStoreLatencyMillis; + } + + /** Returns time spent on indexing, in milliseconds. */ + public int getNativeIndexLatencyMillis() { + return mNativeIndexLatencyMillis; + } + + /** Returns time spent on merging indices, in milliseconds. */ + public int getNativeIndexMergeLatencyMillis() { + return mNativeIndexMergeLatencyMillis; + } + + /** Returns document size, in bytes. */ + public int getNativeDocumentSizeBytes() { + return mNativeDocumentSizeBytes; + } + + /** Returns number of tokens indexed. */ + public int getNativeNumTokensIndexed() { + return mNativeNumTokensIndexed; + } + + /** Returns number of tokens clipped for exceeding the max number. */ + public int getNativeNumTokensClipped() { + return mNativeNumTokensClipped; + } + + /** Builder for {@link PutDocumentStats}. */ + public static class Builder { + @NonNull final GeneralStats mGeneralStats; + int mGenerateDocumentProtoLatencyMillis; + int mRewriteDocumentTypesLatencyMillis; + int mNativeLatencyMillis; + int mNativeDocumentStoreLatencyMillis; + int mNativeIndexLatencyMillis; + int mNativeIndexMergeLatencyMillis; + int mNativeDocumentSizeBytes; + int mNativeNumTokensIndexed; + int mNativeNumTokensClipped; + + /** Builder takes {@link GeneralStats} to hold general stats. */ + public Builder(@NonNull GeneralStats generalStats) { + mGeneralStats = Preconditions.checkNotNull(generalStats); + } + + /** Sets how much time we spend for generating document proto, in milliseconds. */ + @NonNull + public Builder setGenerateDocumentProtoLatencyMillis( + int generateDocumentProtoLatencyMillis) { + mGenerateDocumentProtoLatencyMillis = generateDocumentProtoLatencyMillis; + return this; + } + + /** + * Sets how much time we spend for rewriting types and namespaces in document, in + * milliseconds. + */ + @NonNull + public Builder setRewriteDocumentTypesLatencyMillis(int rewriteDocumentTypesLatencyMillis) { + mRewriteDocumentTypesLatencyMillis = rewriteDocumentTypesLatencyMillis; + return this; + } + + /** Sets the native latency, in milliseconds. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets how much time we spend on document store, in milliseconds. */ + @NonNull + public Builder setNativeDocumentStoreLatencyMillis(int nativeDocumentStoreLatencyMillis) { + mNativeDocumentStoreLatencyMillis = nativeDocumentStoreLatencyMillis; + return this; + } + + /** Sets the native index latency, in milliseconds. */ + @NonNull + public Builder setNativeIndexLatencyMillis(int nativeIndexLatencyMillis) { + mNativeIndexLatencyMillis = nativeIndexLatencyMillis; + return this; + } + + /** Sets how much time we spend on merging indices, in milliseconds. */ + @NonNull + public Builder setNativeIndexMergeLatencyMillis(int nativeIndexMergeLatencyMillis) { + mNativeIndexMergeLatencyMillis = nativeIndexMergeLatencyMillis; + return this; + } + + /** Sets document size, in bytes. */ + @NonNull + public Builder setNativeDocumentSizeBytes(int nativeDocumentSizeBytes) { + mNativeDocumentSizeBytes = nativeDocumentSizeBytes; + return this; + } + + /** Sets number of tokens indexed in native. */ + @NonNull + public Builder setNativeNumTokensIndexed(int nativeNumTokensIndexed) { + mNativeNumTokensIndexed = nativeNumTokensIndexed; + return this; + } + + /** Sets number of tokens clipped for exceeding the max number. */ + @NonNull + public Builder setNativeNumTokensClipped(int nativeNumTokensClipped) { + mNativeNumTokensClipped = nativeNumTokensClipped; + return this; + } + + /** + * Creates a new {@link PutDocumentStats} object from the contents of this {@link Builder} + * instance. + */ + @NonNull + public PutDocumentStats build() { + return new PutDocumentStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index d076db3b8f82..fc0299ef88af 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Ia9a8daef1a6d7d9432f7808d440abd64f4797701 +I895f5fb3bcb4be0642c6193000e57d80aafe2166 diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java index ea21e19b2bea..34c7ccbd4df1 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java @@ -90,11 +90,11 @@ public interface AppSearchSessionShim extends Closeable { * <p>It is a no-op to set the same schema as has been previously set; this is handled * efficiently. * - * <p>By default, documents are visible on platform surfaces. To opt out, call - * {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} with {@code visible} as - * false. Any visibility settings apply only to the schemas that are included in the - * {@code request}. Visibility settings for a schema type do not persist across - * {@link #setSchema} calls. + * <p>By default, documents are visible on platform surfaces. To opt out, call {@code + * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any + * visibility settings apply only to the schemas that are included in the {@code request}. + * Visibility settings for a schema type do not apply or persist across {@link + * SetSchemaRequest}s. * * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old * schema. You can save your documents by setting {@link @@ -118,6 +118,8 @@ public interface AppSearchSessionShim extends Closeable { * @see android.app.appsearch.AppSearchSchema.Migrator * @see android.app.appsearch.AppSearchMigrationHelper.Transformer */ + // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are + // exposed. @NonNull ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request); @@ -132,15 +134,17 @@ public interface AppSearchSessionShim extends Closeable { ListenableFuture<Set<AppSearchSchema>> getSchema(); /** - * Indexes documents into AppSearch. + * Indexes documents into the {@link AppSearchSessionShim} database. * - * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a - * schema type previously registered via the {@link #setSchema} method. + * <p>Each {@link GenericDocument} object must have a {@code schemaType} field set to an {@link + * AppSearchSchema} type that has been previously registered by calling the {@link #setSchema} + * method. * - * @param request {@link PutDocumentsRequest} containing documents to be indexed - * @return The pending result of performing this operation. The keys of the returned {@link - * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if - * they were successfully indexed, or a failed {@link AppSearchResult} otherwise. + * @param request containing documents to be indexed. + * @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The + * keys of the returned {@link AppSearchBatchResult} are the URIs of the input documents. + * The values are either {@code null} if the corresponding document was successfully + * indexed, or a failed {@link AppSearchResult} otherwise. */ @NonNull ListenableFuture<AppSearchBatchResult<String, Void>> put(@NonNull PutDocumentsRequest request); @@ -213,7 +217,7 @@ public interface AppSearchSessionShim extends Closeable { * adding projection, can be set by calling the corresponding {@link SearchSpec.Builder} setter. * * <p>This method is lightweight. The heavy work will be done in {@link - * SearchResultsShim#getNextPage()}. + * SearchResultsShim#getNextPage}. * * @param queryExpression query string to search. * @param searchSpec spec for setting document filters, adding projection, setting term match diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java index 31c934f8bb27..d912c08e7d5f 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java @@ -37,11 +37,11 @@ public interface GlobalSearchSessionShim extends Closeable { * SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi}, or {@link * SetSchemaRequest.Builder#setDocumentClassVisibilityForSystemUi} when building a schema. * - * <p>See {@link AppSearchSessionShim#search(String, SearchSpec)} for a detailed explanation on - * forming a query string. + * <p>See {@link AppSearchSessionShim#search} for a detailed explanation on forming a query + * string. * * <p>This method is lightweight. The heavy work will be done in {@link - * SearchResultsShim#getNextPage()}. + * SearchResultsShim#getNextPage}. * * @param queryExpression query string to search. * @param searchSpec spec for setting document filters, adding projection, setting term match diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java index 328c65ca2727..38f61f83d24e 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java @@ -24,25 +24,29 @@ import java.io.Closeable; import java.util.List; /** - * SearchResultsShim are a returned object from a query API. + * Encapsulates results of a search operation. * - * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based - * on request. + * <p>Each {@link AppSearchSessionShim#search} operation returns a list of {@link SearchResult} + * objects, referred to as a "page", limited by the size configured by {@link + * SearchSpec.Builder#setResultCountPerPage}. * - * <p>Should close this object after finish fetching results. + * <p>To fetch a page of results, call {@link #getNextPage()}. + * + * <p>All instances of {@link SearchResultsShim} must call {@link SearchResultsShim#close()} after + * the results are fetched. * * <p>This class is not thread safe. */ public interface SearchResultsShim extends Closeable { /** - * Gets a whole page of {@link SearchResult}s. + * Retrieves the next page of {@link SearchResult} objects. * - * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty - * list. + * <p>The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}. * - * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}. + * <p>Continue calling this method to access results until it returns an empty list, signifying + * there are no more results. * - * @return The pending result of performing this operation. + * @return a {@link ListenableFuture} which resolves to a list of {@link SearchResult} objects. */ @NonNull ListenableFuture<List<SearchResult>> getNextPage(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index c5d3b7a726b9..ac6eb3229a25 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -53,7 +53,6 @@ import android.net.Uri; import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.LimitExceededException; import android.os.Looper; @@ -152,9 +151,6 @@ public class JobSchedulerService extends com.android.server.SystemService private static final boolean ENFORCE_MAX_JOBS = true; /** The maximum number of jobs that we allow an unprivileged app to schedule */ private static final int MAX_JOBS_PER_APP = 100; - /** The number of the most recently completed jobs to keep track of for debugging purposes. */ - private static final int NUM_COMPLETED_JOB_HISTORY = - Build.IS_USERDEBUG || Build.IS_ENG ? 25 : 0; @VisibleForTesting public static Clock sSystemClock = Clock.systemUTC(); @@ -301,10 +297,6 @@ public class JobSchedulerService extends com.android.server.SystemService */ boolean mReportedActive; - private int mLastCompletedJobIndex = 0; - private final JobStatus[] mLastCompletedJobs = new JobStatus[NUM_COMPLETED_JOB_HISTORY]; - private final long[] mLastCompletedJobTimeElapsed = new long[NUM_COMPLETED_JOB_HISTORY]; - /** * A mapping of which uids are currently in the foreground to their effective priority. */ @@ -1760,10 +1752,6 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule); } - mLastCompletedJobs[mLastCompletedJobIndex] = jobStatus; - mLastCompletedJobTimeElapsed[mLastCompletedJobIndex] = sElapsedRealtimeClock.millis(); - mLastCompletedJobIndex = (mLastCompletedJobIndex + 1) % NUM_COMPLETED_JOB_HISTORY; - // Intentionally not checking expedited job quota here. An app can't find out if it's run // out of quota when it asks JS to reschedule an expedited job. Instead, the rescheduled // EJ will just be demoted to a regular job if the app has no EJ quota left. @@ -3310,37 +3298,6 @@ public class JobSchedulerService extends com.android.server.SystemService } } pw.decreaseIndent(); - - pw.println(); - boolean recentPrinted = false; - pw.println("Recently completed jobs:"); - pw.increaseIndent(); - for (int r = 1; r <= NUM_COMPLETED_JOB_HISTORY; ++r) { - // Print most recent first - final int idx = (mLastCompletedJobIndex + NUM_COMPLETED_JOB_HISTORY - r) - % NUM_COMPLETED_JOB_HISTORY; - final JobStatus job = mLastCompletedJobs[idx]; - if (job != null) { - if (!predicate.test(job)) { - continue; - } - recentPrinted = true; - TimeUtils.formatDuration(mLastCompletedJobTimeElapsed[idx], nowElapsed, pw); - pw.println(); - // Double indent for readability - pw.increaseIndent(); - pw.increaseIndent(); - job.dump(pw, true, nowElapsed); - pw.decreaseIndent(); - pw.decreaseIndent(); - } - } - if (!recentPrinted) { - pw.println("None"); - } - pw.decreaseIndent(); - pw.println(); - if (filterUid == -1) { pw.println(); pw.print("mReadyToRock="); pw.println(mReadyToRock); diff --git a/cmds/hid/OWNERS b/cmds/hid/OWNERS new file mode 100644 index 000000000000..d701f23cb9b8 --- /dev/null +++ b/cmds/hid/OWNERS @@ -0,0 +1 @@ +include /core/java/android/hardware/input/OWNERS diff --git a/core/api/current.txt b/core/api/current.txt index 5b639ff0b00f..78b4f80cd791 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -528,6 +528,8 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 + field public static final int dialTint = 16844342; // 0x1010636 + field public static final int dialTintMode = 16844343; // 0x1010637 field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 @@ -725,8 +727,14 @@ package android { field public static final int groupIndicator = 16843019; // 0x101010b field public static final int gwpAsanMode = 16844310; // 0x1010616 field public static final int hand_hour = 16843011; // 0x1010103 + field public static final int hand_hourTint = 16844344; // 0x1010638 + field public static final int hand_hourTintMode = 16844345; // 0x1010639 field public static final int hand_minute = 16843012; // 0x1010104 + field public static final int hand_minuteTint = 16844346; // 0x101063a + field public static final int hand_minuteTintMode = 16844347; // 0x101063b field public static final int hand_second = 16844323; // 0x1010623 + field public static final int hand_secondTint = 16844348; // 0x101063c + field public static final int hand_secondTintMode = 16844349; // 0x101063d field public static final int handle = 16843354; // 0x101025a field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e @@ -18551,23 +18559,6 @@ package android.hardware.camera2.params { package android.hardware.display { - public final class DeviceProductInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getConnectionToSinkType(); - method public int getManufactureWeek(); - method public int getManufactureYear(); - method @NonNull public String getManufacturerPnpId(); - method public int getModelYear(); - method @Nullable public String getName(); - method @NonNull public String getProductId(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1 - field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2 - field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3 - field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR; - } - public final class DisplayManager { method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int); method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler); @@ -26288,6 +26279,7 @@ package android.net { field public static final int NET_CAPABILITY_CBS = 5; // 0x5 field public static final int NET_CAPABILITY_DUN = 2; // 0x2 field public static final int NET_CAPABILITY_EIMS = 10; // 0xa + field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13 field public static final int NET_CAPABILITY_FOTA = 3; // 0x3 field public static final int NET_CAPABILITY_IA = 7; // 0x7 @@ -30655,8 +30647,8 @@ package android.os { } public final class BugreportManager { - method public void cancelBugreport(); - method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + method @WorkerThread public void cancelBugreport(); + method @WorkerThread public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); } public abstract static class BugreportManager.BugreportCallback { @@ -41234,6 +41226,7 @@ package android.telephony { field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41 + field public static final int ALL_MATCHING_RULES_FAILED = 2254; // 0x8ce field public static final int APN_DISABLED = 2045; // 0x7fd field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b field public static final int APN_MISMATCH = 2054; // 0x806 @@ -41383,6 +41376,7 @@ package android.telephony { field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845 field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f field public static final int MAC_FAILURE = 2183; // 0x887 + field public static final int MATCH_ALL_RULE_NOT_ALLOWED = 2253; // 0x8cd field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876 field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f @@ -46696,7 +46690,6 @@ package android.view { method public long getAppVsyncOffsetNanos(); method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point); method @Nullable public android.view.DisplayCutout getCutout(); - method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo(); method public int getDisplayId(); method public int getFlags(); method public android.view.Display.HdrCapabilities getHdrCapabilities(); @@ -53383,6 +53376,7 @@ package android.widget { method public int getCheckedItemPosition(); method public android.util.SparseBooleanArray getCheckedItemPositions(); method public int getChoiceMode(); + method public int getEdgeEffectType(); method public int getListPaddingBottom(); method public int getListPaddingLeft(); method public int getListPaddingRight(); @@ -53424,6 +53418,7 @@ package android.widget { method public void setChoiceMode(int); method public void setDrawSelectorOnTop(boolean); method public void setEdgeEffectColor(@ColorInt int); + method public void setEdgeEffectType(int); method public void setFastScrollAlwaysVisible(boolean); method public void setFastScrollEnabled(boolean); method public void setFastScrollStyle(int); @@ -53714,11 +53709,27 @@ package android.widget { ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet); ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int); ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int, int); + method @Deprecated @Nullable public android.graphics.BlendMode getDialTintBlendMode(); + method @Deprecated @Nullable public android.content.res.ColorStateList getDialTintList(); + method @Deprecated @Nullable public android.graphics.BlendMode getHourHandTintBlendMode(); + method @Deprecated @Nullable public android.content.res.ColorStateList getHourHandTintList(); + method @Deprecated @Nullable public android.graphics.BlendMode getMinuteHandTintBlendMode(); + method @Deprecated @Nullable public android.content.res.ColorStateList getMinuteHandTintList(); + method @Deprecated @Nullable public android.graphics.BlendMode getSecondHandTintBlendMode(); + method @Deprecated @Nullable public android.content.res.ColorStateList getSecondHandTintList(); method @Deprecated @Nullable public String getTimeZone(); method @Deprecated public void setDial(@NonNull android.graphics.drawable.Icon); + method @Deprecated public void setDialTintBlendMode(@Nullable android.graphics.BlendMode); + method @Deprecated public void setDialTintList(@Nullable android.content.res.ColorStateList); method @Deprecated public void setHourHand(@NonNull android.graphics.drawable.Icon); + method @Deprecated public void setHourHandTintBlendMode(@Nullable android.graphics.BlendMode); + method @Deprecated public void setHourHandTintList(@Nullable android.content.res.ColorStateList); method @Deprecated public void setMinuteHand(@NonNull android.graphics.drawable.Icon); + method @Deprecated public void setMinuteHandTintBlendMode(@Nullable android.graphics.BlendMode); + method @Deprecated public void setMinuteHandTintList(@Nullable android.content.res.ColorStateList); method @Deprecated public void setSecondHand(@Nullable android.graphics.drawable.Icon); + method @Deprecated public void setSecondHandTintBlendMode(@Nullable android.graphics.BlendMode); + method @Deprecated public void setSecondHandTintList(@Nullable android.content.res.ColorStateList); method @Deprecated public void setTimeZone(@Nullable String); } @@ -54416,6 +54427,7 @@ package android.widget { method public boolean executeKeyEvent(android.view.KeyEvent); method public void fling(int); method public boolean fullScroll(int); + method public int getEdgeEffectType(); method @ColorInt public int getLeftEdgeEffectColor(); method public int getMaxScrollAmount(); method @ColorInt public int getRightEdgeEffectColor(); @@ -54423,6 +54435,7 @@ package android.widget { method public boolean isSmoothScrollingEnabled(); method public boolean pageScroll(int); method public void setEdgeEffectColor(@ColorInt int); + method public void setEdgeEffectType(int); method public void setFillViewport(boolean); method public void setLeftEdgeEffectColor(@ColorInt int); method public void setRightEdgeEffectColor(@ColorInt int); @@ -55276,6 +55289,7 @@ package android.widget { method public void fling(int); method public boolean fullScroll(int); method @ColorInt public int getBottomEdgeEffectColor(); + method public int getEdgeEffectType(); method public int getMaxScrollAmount(); method @ColorInt public int getTopEdgeEffectColor(); method public boolean isFillViewport(); @@ -55284,6 +55298,7 @@ package android.widget { method public void scrollToDescendant(@NonNull android.view.View); method public void setBottomEdgeEffectColor(@ColorInt int); method public void setEdgeEffectColor(@ColorInt int); + method public void setEdgeEffectType(int); method public void setFillViewport(boolean); method public void setSmoothScrollingEnabled(boolean); method public void setTopEdgeEffectColor(@ColorInt int); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 5dc1cd7a3173..dd9582fddd4a 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -189,6 +189,10 @@ package android.net { field public static final int TRANSPORT_TEST = 7; // 0x7 } + public class NetworkWatchlistManager { + method @Nullable public byte[] getWatchlistConfigHash(); + } + public final class Proxy { method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index a5d40a63a795..ff4fc9508ce7 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1826,7 +1826,7 @@ package android.bluetooth { method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1 field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2 @@ -1942,6 +1942,10 @@ package android.bluetooth { field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; } + public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.SEND_SMS) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent); + } + public final class BluetoothPan implements android.bluetooth.BluetoothProfile { method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice); @@ -1974,6 +1978,7 @@ package android.bluetooth { field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0 field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff field public static final int HEADSET_CLIENT = 16; // 0x10 + field public static final int MAP_CLIENT = 18; // 0x12 field public static final int PAN = 5; // 0x5 field public static final int PBAP_CLIENT = 17; // 0x11 field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0 @@ -2027,7 +2032,7 @@ package android.bluetooth { public final class BufferConstraints implements android.os.Parcelable { ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>); method public int describeContents(); - method @Nullable public android.bluetooth.BufferConstraint getCodec(int); + method @Nullable public android.bluetooth.BufferConstraint forCodec(int); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20 field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR; @@ -4683,6 +4688,7 @@ package android.location { } public class LocationManager { + method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener); method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>); method @Nullable public String getExtraLocationControllerPackage(); @@ -4697,7 +4703,7 @@ package android.location { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String); method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback); - method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerProviderRequestListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.Listener); + method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); @@ -4706,7 +4712,6 @@ package android.location { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle); method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback); - method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void unregisterProviderRequestListener(@NonNull android.location.provider.ProviderRequest.Listener); } public final class LocationRequest implements android.os.Parcelable { @@ -4856,7 +4861,7 @@ package android.location.provider { method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource); } - public static interface ProviderRequest.Listener { + public static interface ProviderRequest.ChangedListener { method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest); } @@ -5067,7 +5072,7 @@ package android.media { } public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation { - method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener, @Nullable android.os.Handler); + method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener); } public static interface MediaPlayer.OnRtpRxNoticeListener { @@ -7911,6 +7916,28 @@ package android.net.util { } +package android.net.vcn { + + public class VcnManager { + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); + method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener); + } + + public static interface VcnManager.VcnNetworkPolicyListener { + method public void onPolicyChanged(); + } + + public final class VcnNetworkPolicyResult implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public boolean isTeardownRequested(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnNetworkPolicyResult> CREATOR; + } + +} + package android.net.wifi { public final class WifiMigration { @@ -8258,7 +8285,7 @@ package android.os { public final class BugreportManager { method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence); - method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + method @RequiresPermission(android.Manifest.permission.DUMP) @WorkerThread public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); } public final class BugreportParams { @@ -9191,6 +9218,7 @@ package android.provider { field public static final String NAMESPACE_PERMISSIONS = "permissions"; field public static final String NAMESPACE_PRIVACY = "privacy"; field public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot"; + field public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness"; field public static final String NAMESPACE_ROLLBACK = "rollback"; field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; field public static final String NAMESPACE_RUNTIME = "runtime"; @@ -12223,6 +12251,7 @@ package android.telephony.data { method public long getRetryDurationMillis(); method @Nullable public android.telephony.data.SliceInfo getSliceInfo(); method @Deprecated public int getSuggestedRetryTime(); + method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 @@ -12258,6 +12287,7 @@ package android.telephony.data { method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long); method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo); method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int); + method @NonNull public android.telephony.data.DataCallResponse.Builder setTrafficDescriptors(@NonNull java.util.List<android.telephony.data.TrafficDescriptor>); } public final class DataProfile implements android.os.Parcelable { @@ -12328,7 +12358,7 @@ package android.telephony.data { method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback); - method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback); + method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback); } public class DataServiceCallback { @@ -12427,6 +12457,15 @@ package android.telephony.data { method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int); } + public final class TrafficDescriptor implements android.os.Parcelable { + ctor public TrafficDescriptor(@Nullable String, @Nullable String); + method public int describeContents(); + method @Nullable public String getDnn(); + method @Nullable public String getOsAppId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR; + } + } package android.telephony.euicc { @@ -14246,21 +14285,10 @@ package android.uwb { public final class UwbManager { method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getAngleOfArrivalSupport(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerInitiatorSession(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerResponderSession(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxSimultaneousSessions(); method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo(); - method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.List<java.lang.Integer> getSupportedChannelNumbers(); - method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public boolean isRangingSupported(); method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback); - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1 } public static interface UwbManager.AdapterStateCallback { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index a02320dbb70a..f0a2a492c3cf 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -580,6 +580,14 @@ package android.app.usage { } +package android.appwidget { + + public class AppWidgetManager { + method public void setBindAppWidgetPermission(@NonNull String, int, boolean); + } + +} + package android.bluetooth { public final class BluetoothClass implements android.os.Parcelable { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index dd5a9a8a28af..e16e40b6d572 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -47,6 +47,7 @@ import android.app.usage.IUsageStatsManager; import android.app.usage.NetworkStatsManager; import android.app.usage.StorageStatsManager; import android.app.usage.UsageStatsManager; +import android.apphibernation.AppHibernationManager; import android.appwidget.AppWidgetManager; import android.bluetooth.BluetoothManager; import android.companion.CompanionDeviceManager; @@ -1378,6 +1379,13 @@ public final class SystemServiceRegistry { IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE); return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b)); }}); + registerService(Context.APP_HIBERNATION_SERVICE, AppHibernationManager.class, + new CachedServiceFetcher<AppHibernationManager>() { + @Override + public AppHibernationManager createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(Context.APP_HIBERNATION_SERVICE); + return b == null ? null : new AppHibernationManager(ctx); + }}); registerService(Context.DREAM_SERVICE, DreamManager.class, new CachedServiceFetcher<DreamManager>() { @Override diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index aac8710e8691..38919f61d9df 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -23,6 +23,8 @@ import android.annotation.RequiresFeature; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; +import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.app.IServiceConnection; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; @@ -1095,7 +1097,9 @@ public class AppWidgetManager { * * @hide */ - public void setBindAppWidgetPermission(String packageName, int userId, boolean permission) { + @TestApi + public void setBindAppWidgetPermission( + @NonNull String packageName, @UserIdInt int userId, boolean permission) { if (mService == null) { return; } diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index cd91aa9b16b7..53aaae0470e2 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -943,12 +943,13 @@ public final class BluetoothA2dp implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) { - if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")"); + public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec, + int value) { + if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")"); try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return service.setBufferMillis(codec, value); + return service.setBufferLengthMillis(codec, value); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return false; diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index ec46da0dcf0e..8d4157259ff7 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -3654,12 +3654,12 @@ public final class BluetoothAdapter { } @Override - public void onDeviceDisconnected(BluetoothDevice device) { + public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); Executor executor = callbackExecutorEntry.getValue(); - executor.execute(() -> callback.onDeviceDisconnected(device)); + executor.execute(() -> callback.onDeviceDisconnected(device, hciReason)); } } }; @@ -3764,8 +3764,155 @@ public final class BluetoothAdapter { /** * Callback triggered when a bluetooth device (classic or BLE) is disconnected * @param device is the disconnected bluetooth device + * @param reason is the disconnect reason */ - public void onDeviceDisconnected(BluetoothDevice device) {} + public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {} + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "REASON_" }, value = { + REASON_UNKNOWN, + REASON_LOCAL_REQUEST, + REASON_REMOTE_REQUEST, + REASON_LOCAL_ERROR, + REASON_REMOTE_ERROR, + REASON_TIMEOUT, + REASON_SECURITY, + REASON_SYSTEM_POLICY, + REASON_RESOURCE_LIMIT_REACHED, + REASON_CONNECTION_EXISTS, + REASON_BAD_PARAMETERS}) + public @interface DisconnectReason {} + + /** + * Indicates that the ACL disconnected due to an unknown reason. + */ + public static final int REASON_UNKNOWN = 0; + + /** + * Indicates that the ACL disconnected due to an explicit request from the local device. + * <p> + * Example cause: This is a normal disconnect reason, e.g., user/app initiates + * disconnection. + */ + public static final int REASON_LOCAL_REQUEST = 1; + + /** + * Indicates that the ACL disconnected due to an explicit request from the remote device. + * <p> + * Example cause: This is a normal disconnect reason, e.g., user/app initiates + * disconnection. + * <p> + * Example solution: The app can also prompt the user to check their remote device. + */ + public static final int REASON_REMOTE_REQUEST = 2; + + /** + * Generic disconnect reason indicating the ACL disconnected due to an error on the local + * device. + * <p> + * Example solution: Prompt the user to check their local device (e.g., phone, car + * headunit). + */ + public static final int REASON_LOCAL_ERROR = 3; + + /** + * Generic disconnect reason indicating the ACL disconnected due to an error on the remote + * device. + * <p> + * Example solution: Prompt the user to check their remote device (e.g., headset, car + * headunit, watch). + */ + public static final int REASON_REMOTE_ERROR = 4; + + /** + * Indicates that the ACL disconnected due to a timeout. + * <p> + * Example cause: remote device might be out of range. + * <p> + * Example solution: Prompt user to verify their remote device is on or in + * connection/pairing mode. + */ + public static final int REASON_TIMEOUT = 5; + + /** + * Indicates that the ACL disconnected due to link key issues. + * <p> + * Example cause: Devices are either unpaired or remote device is refusing our pairing + * request. + * <p> + * Example solution: Prompt user to unpair and pair again. + */ + public static final int REASON_SECURITY = 6; + + /** + * Indicates that the ACL disconnected due to the local device's system policy. + * <p> + * Example cause: privacy policy, power management policy, permissions, etc. + * <p> + * Example solution: Prompt the user to check settings, or check with their system + * administrator (e.g. some corp-managed devices do not allow OPP connection). + */ + public static final int REASON_SYSTEM_POLICY = 7; + + /** + * Indicates that the ACL disconnected due to resource constraints, either on the local + * device or the remote device. + * <p> + * Example cause: controller is busy, memory limit reached, maximum number of connections + * reached. + * <p> + * Example solution: The app should wait and try again. If still failing, prompt the user + * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device. + */ + public static final int REASON_RESOURCE_LIMIT_REACHED = 8; + + /** + * Indicates that the ACL disconnected because another ACL connection already exists. + */ + public static final int REASON_CONNECTION_EXISTS = 9; + + /** + * Indicates that the ACL disconnected due to incorrect parameters passed in from the app. + * <p> + * Example solution: Change parameters and try again. If error persists, the app can report + * telemetry and/or log the error in a bugreport. + */ + public static final int REASON_BAD_PARAMETERS = 10; + + /** + * Returns human-readable strings corresponding to {@link DisconnectReason}. + */ + public static String disconnectReasonText(@DisconnectReason int reason) { + switch (reason) { + case REASON_UNKNOWN: + return "Reason unknown"; + case REASON_LOCAL_REQUEST: + return "Local request"; + case REASON_REMOTE_REQUEST: + return "Remote request"; + case REASON_LOCAL_ERROR: + return "Local error"; + case REASON_REMOTE_ERROR: + return "Remote error"; + case REASON_TIMEOUT: + return "Timeout"; + case REASON_SECURITY: + return "Security"; + case REASON_SYSTEM_POLICY: + return "System policy"; + case REASON_RESOURCE_LIMIT_REACHED: + return "Resource constrained"; + case REASON_CONNECTION_EXISTS: + return "Connection already exists"; + case REASON_BAD_PARAMETERS: + return "Bad parameters"; + default: + return "Unrecognized disconnect reason: " + reason; + } + } } /** diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java index ff6cffb272a5..0312a2190a4b 100644 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ b/core/java/android/bluetooth/BluetoothMapClient.java @@ -18,7 +18,9 @@ package android.bluetooth; import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -30,6 +32,7 @@ import android.os.RemoteException; import android.util.Log; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -37,44 +40,60 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothMapClient implements BluetoothProfile { private static final String TAG = "BluetoothMapClient"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE); + /** @hide */ public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED"; + /** @hide */ public static final String ACTION_MESSAGE_RECEIVED = "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED"; /* Actions to be used for pending intents */ + /** @hide */ public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY = "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY"; + /** @hide */ public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY = "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY"; /** * Action to notify read status changed + * + * @hide */ public static final String ACTION_MESSAGE_READ_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED"; /** * Action to notify deleted status changed + * + * @hide */ public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED"; - /* Extras used in ACTION_MESSAGE_RECEIVED intent. - * NOTE: HANDLE is only valid for a single session with the device. */ + /** + * Extras used in ACTION_MESSAGE_RECEIVED intent. + * NOTE: HANDLE is only valid for a single session with the device. + */ + /** @hide */ public static final String EXTRA_MESSAGE_HANDLE = "android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE"; + /** @hide */ public static final String EXTRA_MESSAGE_TIMESTAMP = "android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP"; + /** @hide */ public static final String EXTRA_MESSAGE_READ_STATUS = "android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS"; + /** @hide */ public static final String EXTRA_SENDER_CONTACT_URI = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI"; + /** @hide */ public static final String EXTRA_SENDER_CONTACT_NAME = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; @@ -84,6 +103,8 @@ public final class BluetoothMapClient implements BluetoothProfile { * Possible values are: * true: deleted * false: undeleted + * + * @hide */ public static final String EXTRA_MESSAGE_DELETED_STATUS = "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS"; @@ -93,24 +114,42 @@ public final class BluetoothMapClient implements BluetoothProfile { * Possible values are: * 0: failure * 1: success + * + * @hide */ public static final String EXTRA_RESULT_CODE = "android.bluetooth.device.extra.RESULT_CODE"; - /** There was an error trying to obtain the state */ + /** + * There was an error trying to obtain the state + * @hide + */ public static final int STATE_ERROR = -1; + /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; - /** Connection canceled before completion. */ + /** + * Connection canceled before completion. + * @hide + */ public static final int RESULT_CANCELED = 2; - + /** @hide */ private static final int UPLOADING_FEATURE_BITMASK = 0x08; - /** Parameters in setMessageStatus */ + /* + * UNREAD, READ, UNDELETED, DELETED are passed as parameters + * to setMessageStatus to indicate the messages new state. + */ + + /** @hide */ public static final int UNREAD = 0; + /** @hide */ public static final int READ = 1; + /** @hide */ public static final int UNDELETED = 2; + /** @hide */ public static final int DELETED = 3; private BluetoothAdapter mAdapter; @@ -132,19 +171,12 @@ public final class BluetoothMapClient implements BluetoothProfile { mProfileConnector.connect(context, listener); } - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } - } - /** * Close the connection to the backing service. * Other public functions of BluetoothMap will return default error * results once close() has been called. Multiple invocations of close() * are ok. + * @hide */ public void close() { mProfileConnector.disconnect(); @@ -158,6 +190,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * Returns true if the specified Bluetooth device is connected. * Returns false if not connected, or if this proxy object is not * currently connected to the Map service. + * @hide */ public boolean isConnected(BluetoothDevice device) { if (VDBG) Log.d(TAG, "isConnected(" + device + ")"); @@ -225,6 +258,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * Get the list of connected devices. Currently at most one. * * @return list of connected devices + * @hide */ @Override public List<BluetoothDevice> getConnectedDevices() { @@ -246,6 +280,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * Get the list of devices matching specified states. Currently at most one. * * @return list of matching devices + * @hide */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { @@ -267,6 +302,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * Get connection state of device * * @return device connection state + * @hide */ @Override public int getConnectionState(BluetoothDevice device) { @@ -383,11 +419,44 @@ public final class BluetoothMapClient implements BluetoothProfile { * Send an SMS message to either the contacts primary number or the telephone number specified. * * @param device Bluetooth device + * @param contacts Uri Collection of the contacts + * @param message Message to be sent + * @param sentIntent intent issued when message is sent + * @param deliveredIntent intent issued when message is delivered + * @return true if the message is enqueued, false on error + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.SEND_SMS) + public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts, + @NonNull String message, @Nullable PendingIntent sentIntent, + @Nullable PendingIntent deliveredIntent) { + if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message); + final IBluetoothMapClient service = getService(); + if (service != null && isEnabled() && isValidDevice(device)) { + try { + return service.sendMessage(device, contacts.toArray(new Uri[contacts.size()]), + message, sentIntent, deliveredIntent); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + return false; + } + + /** + * Send a message. + * + * Send an SMS message to either the contacts primary number or the telephone number specified. + * + * @param device Bluetooth device * @param contacts Uri[] of the contacts * @param message Message to be sent * @param sentIntent intent issued when message is sent * @param deliveredIntent intent issued when message is delivered * @return true if the message is enqueued, false on error + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message, @@ -410,6 +479,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * * @param device Bluetooth device * @return true if the message is enqueued, false on error + * @hide */ public boolean getUnreadMessages(BluetoothDevice device) { if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")"); @@ -431,6 +501,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * @param device The Bluetooth device to get this value for. * @return Returns true if the Uploading bit value in SDP record's * MapSupportedFeatures field is set. False is returned otherwise. + * @hide */ public boolean isUploadingSupported(BluetoothDevice device) { final IBluetoothMapClient service = getService(); @@ -457,7 +528,7 @@ public final class BluetoothMapClient implements BluetoothProfile { * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for * "deleted", otherwise return error * @return <code>true</code> if request has been sent, <code>false</code> on error - * + * @hide */ @RequiresPermission(Manifest.permission.READ_SMS) public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index c31b04e81456..201d6c495d98 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -186,6 +186,7 @@ public interface BluetoothProfile { * * @hide */ + @SystemApi int MAP_CLIENT = 18; /** diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java index 7e5ec1e78435..97d97232b7a6 100644 --- a/core/java/android/bluetooth/BufferConstraints.java +++ b/core/java/android/bluetooth/BufferConstraints.java @@ -90,7 +90,7 @@ public final class BufferConstraints implements Parcelable { * @hide */ @SystemApi - public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) { + public @Nullable BufferConstraint forCodec(@BluetoothCodecConfig.SourceCodecType int codec) { return mBufferConstraints.get(codec); } } diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 76d50bdf414c..43ef33e1f420 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -145,6 +145,12 @@ public interface BiometricConstants { int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; /** + * Authentication cannot proceed because re-enrollment is required. + * @hide + */ + int BIOMETRIC_ERROR_RE_ENROLL = 16; + + /** * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused * because the authentication attempt was unsuccessful. * @hide diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index eafcf529de62..4385b1dac7a0 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -153,6 +153,12 @@ public interface BiometricFaceConstants { int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; /** + * Authentication cannot proceed because re-enrollment is required. + * @hide + */ + int BIOMETRIC_ERROR_RE_ENROLL = 16; + + /** * @hide */ int FACE_ERROR_VENDOR_BASE = 1000; diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index 01f0e71a7c33..30e24d2ec8db 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -166,6 +166,12 @@ public interface BiometricFingerprintConstants { public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; /** + * Authentication cannot proceed because re-enrollment is required. + * @hide + */ + int BIOMETRIC_ERROR_RE_ENROLL = 16; + + /** * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index f9eecaec5bb2..ac6ba0a4ac58 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -378,9 +378,10 @@ public abstract class CameraDevice implements AutoCloseable { * released, continuous repeating requests stopped and any pending * multi-frame capture requests flushed.</p> * - * <p>Note that the CameraExtensionSession currently supports at most two - * multi frame capture surface formats: ImageFormat.YUV_420_888 and - * ImageFormat.JPEG. Clients must query the multi-frame capture format support using + * <p>Note that the CameraExtensionSession currently supports at most wo + * multi frame capture surface formats: ImageFormat.JPEG will be supported + * by all extensions and ImageFormat.YUV_420_888 may or may not be supported. + * Clients must query the multi-frame capture format support using * {@link CameraExtensionCharacteristics#getExtensionSupportedSizes(int, int)}. * For repeating requests CameraExtensionSession supports only * {@link android.graphics.SurfaceTexture} as output. Clients can query the supported resolution diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index d3eb3779189b..6121cd260dc3 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -35,6 +35,7 @@ import android.util.Log; import android.util.Pair; import android.util.Size; +import java.util.HashSet; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -153,12 +154,8 @@ public final class CameraExtensionCharacteristics { mChars = chars; } - private static List<Size> generateSupportedSizes(List<SizeList> sizesList, - Integer format, - StreamConfigurationMap streamMap) { - // Per API contract it is assumed that the extension is able to support all - // camera advertised sizes for a given format in case it doesn't return - // a valid non-empty size list. + private static ArrayList<Size> getSupportedSizes(List<SizeList> sizesList, + Integer format) { ArrayList<Size> ret = new ArrayList<>(); if ((sizesList != null) && (!sizesList.isEmpty())) { for (SizeList entry : sizesList) { @@ -170,13 +167,36 @@ public final class CameraExtensionCharacteristics { } } } + + return ret; + } + + private static List<Size> generateSupportedSizes(List<SizeList> sizesList, + Integer format, + StreamConfigurationMap streamMap) { + // Per API contract it is assumed that the extension is able to support all + // camera advertised sizes for a given format in case it doesn't return + // a valid non-empty size list. + ArrayList<Size> ret = getSupportedSizes(sizesList, format); Size[] supportedSizes = streamMap.getOutputSizes(format); - if (supportedSizes != null) { + if ((ret.isEmpty()) && (supportedSizes != null)) { ret.addAll(Arrays.asList(supportedSizes)); } return ret; } + private static List<Size> generateJpegSupportedSizes(List<SizeList> sizesList, + StreamConfigurationMap streamMap) { + ArrayList<Size> extensionSizes = getSupportedSizes(sizesList, ImageFormat.YUV_420_888); + HashSet<Size> supportedSizes = extensionSizes.isEmpty() ? new HashSet<>(Arrays.asList( + streamMap.getOutputSizes(ImageFormat.YUV_420_888))) : new HashSet<>(extensionSizes); + HashSet<Size> supportedJpegSizes = new HashSet<>(Arrays.asList(streamMap.getOutputSizes( + ImageFormat.JPEG))); + supportedSizes.retainAll(supportedJpegSizes); + + return new ArrayList<>(supportedSizes); + } + /** * A per-process global camera extension manager instance, to track and * initialize/release extensions depending on client activity. @@ -488,8 +508,8 @@ public final class CameraExtensionCharacteristics { * {@link StreamConfigurationMap#getOutputSizes}.</p> * * <p>Device-specific extensions currently support at most two - * multi-frame capture surface formats, ImageFormat.YUV_420_888 or - * ImageFormat.JPEG.</p> + * multi-frame capture surface formats. ImageFormat.JPEG will be supported by all + * extensions and ImageFormat.YUV_420_888 may or may not be supported.</p> * * @param extension the extension type * @param format device-specific extension output format @@ -526,14 +546,17 @@ public final class CameraExtensionCharacteristics { format, streamMap); } else if (format == ImageFormat.JPEG) { extenders.second.init(mCameraId, mChars.getNativeMetadata()); - if (extenders.second.getCaptureProcessor() == null) { + if (extenders.second.getCaptureProcessor() != null) { + // The framework will perform the additional encoding pass on the + // processed YUV_420 buffers. + return generateJpegSupportedSizes( + extenders.second.getSupportedResolutions(), streamMap); + } else { return generateSupportedSizes(null, format, streamMap); } - - return new ArrayList<>(); + } else { + throw new IllegalArgumentException("Unsupported format: " + format); } - - throw new IllegalArgumentException("Unsupported format: " + format); } finally { unregisterClient(clientId); } diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java index 877dfbc49df2..e1b817768461 100644 --- a/core/java/android/hardware/camera2/CameraExtensionSession.java +++ b/core/java/android/hardware/camera2/CameraExtensionSession.java @@ -238,8 +238,10 @@ public abstract class CameraExtensionSession implements AutoCloseable { * from the camera device, to produce a single high-quality output result. * * <p>Note that single capture requests currently do not support - * client parameters. Settings included in the request will - * be entirely overridden by the device-specific extension. </p> + * client parameters except for {@link CaptureRequest#JPEG_ORIENTATION orientation} and + * {@link CaptureRequest#JPEG_QUALITY quality} in case of ImageFormat.JPEG output target. + * The rest of the settings included in the request will be entirely overridden by + * the device-specific extension. </p> * * <p>The {@link CaptureRequest.Builder#addTarget} supports only one * ImageFormat.YUV_420_888 or ImageFormat.JPEG target surface. {@link CaptureRequest} diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java new file mode 100644 index 000000000000..936734b0c711 --- /dev/null +++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java @@ -0,0 +1,312 @@ +/* + * 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.hardware.camera2.impl; + +import android.annotation.NonNull; +import android.graphics.ImageFormat; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.extension.CaptureBundle; +import android.hardware.camera2.extension.ICaptureProcessorImpl; +import android.media.Image; +import android.media.Image.Plane; +import android.media.ImageReader; +import android.media.ImageWriter; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.Surface; + +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; + +// Jpeg compress input YUV and queue back in the client target surface. +public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { + public final static String TAG = "CameraExtensionJpeg"; + private final static int JPEG_QUEUE_SIZE = 1; + private final static int JPEG_DEFAULT_QUALITY = 100; + private final static int JPEG_DEFAULT_ROTATION = 0; + + private final Handler mHandler; + private final HandlerThread mHandlerThread; + private final ICaptureProcessorImpl mProcessor; + + private ImageReader mYuvReader = null; + private android.hardware.camera2.extension.Size mResolution = null; + private int mFormat = -1; + private Surface mOutputSurface = null; + private ImageWriter mOutputWriter = null; + + private static final class JpegParameters { + public HashSet<Long> mTimeStamps = new HashSet<>(); + public int mRotation = JPEG_DEFAULT_ROTATION; // CCW multiple of 90 degrees + public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100] + } + + private ConcurrentLinkedQueue<JpegParameters> mJpegParameters = new ConcurrentLinkedQueue<>(); + + public CameraExtensionJpegProcessor(@NonNull ICaptureProcessorImpl processor) { + mProcessor = processor; + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + + public void close() { + mHandlerThread.quitSafely(); + + if (mOutputWriter != null) { + mOutputWriter.close(); + mOutputWriter = null; + } + + if (mYuvReader != null) { + mYuvReader.close(); + mYuvReader = null; + } + } + + private static JpegParameters getJpegParameters(List<CaptureBundle> captureBundles) { + JpegParameters ret = new JpegParameters(); + if (!captureBundles.isEmpty()) { + // The quality and orientation settings must be equal for requests in a burst + + Byte jpegQuality = captureBundles.get(0).captureResult.get(CaptureResult.JPEG_QUALITY); + if (jpegQuality != null) { + ret.mQuality = jpegQuality; + } else { + Log.w(TAG, "No jpeg quality set, using default: " + JPEG_DEFAULT_QUALITY); + } + + Integer orientation = captureBundles.get(0).captureResult.get( + CaptureResult.JPEG_ORIENTATION); + if (orientation != null) { + ret.mRotation = orientation / 90; + } else { + Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION); + } + + for (CaptureBundle bundle : captureBundles) { + Long timeStamp = bundle.captureResult.get(CaptureResult.SENSOR_TIMESTAMP); + if (timeStamp != null) { + ret.mTimeStamps.add(timeStamp); + } else { + Log.e(TAG, "Capture bundle without valid sensor timestamp!"); + } + } + } + + return ret; + } + + /** + * Compresses a YCbCr image to jpeg, applying a crop and rotation. + * <p> + * The input is defined as a set of 3 planes of 8-bit samples, one plane for + * each channel of Y, Cb, Cr.<br> + * The Y plane is assumed to have the same width and height of the entire + * image.<br> + * The Cb and Cr planes are assumed to be downsampled by a factor of 2, to + * have dimensions (floor(width / 2), floor(height / 2)).<br> + * Each plane is specified by a direct java.nio.ByteBuffer, a pixel-stride, + * and a row-stride. So, the sample at coordinate (x, y) can be retrieved + * from byteBuffer[x * pixel_stride + y * row_stride]. + * <p> + * The pre-compression transformation is applied as follows: + * <ol> + * <li>The image is cropped to the rectangle from (cropLeft, cropTop) to + * (cropRight - 1, cropBottom - 1). So, a cropping-rectangle of (0, 0) - + * (width, height) is a no-op.</li> + * <li>The rotation is applied counter-clockwise relative to the coordinate + * space of the image, so a CCW rotation will appear CW when the image is + * rendered in scanline order. Only rotations which are multiples of + * 90-degrees are suppored, so the parameter 'rot90' specifies which + * multiple of 90 to rotate the image.</li> + * </ol> + * + * @param width the width of the image to compress + * @param height the height of the image to compress + * @param yBuf the buffer containing the Y component of the image + * @param yPStride the stride between adjacent pixels in the same row in + * yBuf + * @param yRStride the stride between adjacent rows in yBuf + * @param cbBuf the buffer containing the Cb component of the image + * @param cbPStride the stride between adjacent pixels in the same row in + * cbBuf + * @param cbRStride the stride between adjacent rows in cbBuf + * @param crBuf the buffer containing the Cr component of the image + * @param crPStride the stride between adjacent pixels in the same row in + * crBuf + * @param crRStride the stride between adjacent rows in crBuf + * @param outBuf a direct java.nio.ByteBuffer to hold the compressed jpeg. + * This must have enough capacity to store the result, or an + * error code will be returned. + * @param outBufCapacity the capacity of outBuf + * @param quality the jpeg-quality (1-100) to use + * @param cropLeft left-edge of the bounds of the image to crop to before + * rotation + * @param cropTop top-edge of the bounds of the image to crop to before + * rotation + * @param cropRight right-edge of the bounds of the image to crop to before + * rotation + * @param cropBottom bottom-edge of the bounds of the image to crop to + * before rotation + * @param rot90 the multiple of 90 to rotate the image CCW (after cropping) + */ + private static native int compressJpegFromYUV420pNative( + int width, int height, + ByteBuffer yBuf, int yPStride, int yRStride, + ByteBuffer cbBuf, int cbPStride, int cbRStride, + ByteBuffer crBuf, int crPStride, int crRStride, + ByteBuffer outBuf, int outBufCapacity, + int quality, + int cropLeft, int cropTop, int cropRight, int cropBottom, + int rot90); + + public void process(List<CaptureBundle> captureBundle) throws RemoteException { + JpegParameters jpegParams = getJpegParameters(captureBundle); + try { + mJpegParameters.add(jpegParams); + mProcessor.process(captureBundle); + } catch (Exception e) { + mJpegParameters.remove(jpegParams); + throw e; + } + } + + public void onOutputSurface(Surface surface, int format) throws RemoteException { + if (format != ImageFormat.JPEG) { + Log.e(TAG, "Unsupported output format: " + format); + return; + } + mOutputSurface = surface; + initializePipeline(); + } + + @Override + public void onResolutionUpdate(android.hardware.camera2.extension.Size size) + throws RemoteException { + mResolution = size; + initializePipeline(); + } + + public void onImageFormatUpdate(int format) throws RemoteException { + if (format != ImageFormat.YUV_420_888) { + Log.e(TAG, "Unsupported input format: " + format); + return; + } + mFormat = format; + initializePipeline(); + } + + private void initializePipeline() throws RemoteException { + if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) && + (mYuvReader == null)) { + // Jpeg/blobs are expected to be configured with (w*h)x1 + mOutputWriter = ImageWriter.newInstance(mOutputSurface, 1 /*maxImages*/, + ImageFormat.JPEG, mResolution.width * mResolution.height, 1); + mYuvReader = ImageReader.newInstance(mResolution.width, mResolution.height, mFormat, + JPEG_QUEUE_SIZE); + mYuvReader.setOnImageAvailableListener(new YuvCallback(), mHandler); + mProcessor.onOutputSurface(mYuvReader.getSurface(), mFormat); + mProcessor.onResolutionUpdate(mResolution); + mProcessor.onImageFormatUpdate(mFormat); + } + } + + @Override + public IBinder asBinder() { + throw new UnsupportedOperationException("Binder IPC not supported!"); + } + + private class YuvCallback implements ImageReader.OnImageAvailableListener { + @Override + public void onImageAvailable(ImageReader reader) { + Image yuvImage = null; + Image jpegImage = null; + try { + yuvImage = mYuvReader.acquireNextImage(); + jpegImage = mOutputWriter.dequeueInputImage(); + } catch (IllegalStateException e) { + if (yuvImage != null) { + yuvImage.close(); + } + if (jpegImage != null) { + jpegImage.close(); + } + Log.e(TAG, "Failed to acquire processed yuv image or jpeg image!"); + return; + } + + ByteBuffer jpegBuffer = jpegImage.getPlanes()[0].getBuffer(); + jpegBuffer.clear(); + // Jpeg/blobs are expected to be configured with (w*h)x1 + int jpegCapacity = jpegImage.getWidth(); + + Plane lumaPlane = yuvImage.getPlanes()[0]; + Plane crPlane = yuvImage.getPlanes()[1]; + Plane cbPlane = yuvImage.getPlanes()[2]; + + Iterator<JpegParameters> jpegIter = mJpegParameters.iterator(); + JpegParameters jpegParams = null; + while(jpegIter.hasNext()) { + JpegParameters currentParams = jpegIter.next(); + if (currentParams.mTimeStamps.contains(yuvImage.getTimestamp())) { + jpegParams = currentParams; + jpegIter.remove(); + break; + } + } + if (jpegParams == null) { + if (mJpegParameters.isEmpty()) { + Log.w(TAG, "Empty jpeg settings queue! Using default jpeg orientation" + + " and quality!"); + jpegParams = new JpegParameters(); + jpegParams.mRotation = JPEG_DEFAULT_ROTATION; + jpegParams.mQuality = JPEG_DEFAULT_QUALITY; + } else { + Log.w(TAG, "No jpeg settings found with matching timestamp for current" + + " processed input!"); + Log.w(TAG, "Using values from the top of the queue!"); + jpegParams = mJpegParameters.poll(); + } + } + + compressJpegFromYUV420pNative( + yuvImage.getWidth(), yuvImage.getHeight(), + lumaPlane.getBuffer(), lumaPlane.getPixelStride(), lumaPlane.getRowStride(), + crPlane.getBuffer(), crPlane.getPixelStride(), crPlane.getRowStride(), + cbPlane.getBuffer(), cbPlane.getPixelStride(), cbPlane.getRowStride(), + jpegBuffer, jpegCapacity, jpegParams.mQuality, + 0, 0, yuvImage.getWidth(), yuvImage.getHeight(), + jpegParams.mRotation); + yuvImage.close(); + + try { + mOutputWriter.queueInputImage(jpegImage); + } catch (IllegalStateException e) { + Log.e(TAG, "Failed to queue encoded result!"); + } finally { + jpegImage.close(); + } + } + } +} diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java index 8451dedb6c37..0a561716d076 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java @@ -91,6 +91,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { private ImageReader mStubCaptureImageReader = null; private ImageWriter mRepeatingRequestImageWriter = null; + private CameraExtensionJpegProcessor mImageJpegProcessor = null; private ICaptureProcessorImpl mImageProcessor = null; private CameraExtensionForwardProcessor mPreviewImageProcessor = null; private IRequestUpdateProcessorImpl mPreviewRequestUpdateProcessor = null; @@ -413,6 +414,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { if (mImageProcessor != null) { if (mClientCaptureSurface != null) { SurfaceInfo surfaceInfo = querySurface(mClientCaptureSurface); + if (surfaceInfo.mFormat == ImageFormat.JPEG) { + mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor); + mImageProcessor = mImageJpegProcessor; + } mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth, surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, mImageExtender.getMaxCaptureStage()); @@ -570,14 +575,16 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { return null; } - // Set user supported jpeg quality and rotation parameters + // This will override the extension capture stage jpeg parameters with the user set + // jpeg quality and rotation. This will guarantee that client configured jpeg + // parameters always have highest priority. Integer jpegRotation = clientRequest.get(CaptureRequest.JPEG_ORIENTATION); if (jpegRotation != null) { - requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation); + captureStage.parameters.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation); } Byte jpegQuality = clientRequest.get(CaptureRequest.JPEG_QUALITY); if (jpegQuality != null) { - requestBuilder.set(CaptureRequest.JPEG_QUALITY, jpegQuality); + captureStage.parameters.set(CaptureRequest.JPEG_QUALITY, jpegQuality); } requestBuilder.addTarget(target); @@ -753,6 +760,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { mPreviewImageProcessor = null; } + if (mImageJpegProcessor != null) { + mImageJpegProcessor.close(); + mImageJpegProcessor = null; + } + mCaptureSession = null; mImageProcessor = null; mCameraRepeatingSurface = mClientRepeatingRequestSurface = null; @@ -1014,7 +1026,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { mCaptureRequestMap.clear(); mCapturePendingMap.clear(); boolean processStatus = true; - List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap); + Byte jpegQuality = mClientRequest.get(CaptureRequest.JPEG_QUALITY); + Integer jpegOrientation = mClientRequest.get(CaptureRequest.JPEG_ORIENTATION); + List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap, + jpegOrientation, jpegQuality); try { mImageProcessor.process(captureList); } catch (RemoteException e) { @@ -1444,10 +1459,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } for (int i = idx; i >= 0; i--) { if (previewMap.valueAt(i).first != null) { - Log.w(TAG, "Discard pending buffer with timestamp: " + previewMap.keyAt(i)); previewMap.valueAt(i).first.close(); } else { - Log.w(TAG, "Discard pending result with timestamp: " + previewMap.keyAt(i)); if (mClientNotificationsEnabled && ((i != idx) || notifyCurrentIndex)) { Log.w(TAG, "Preview frame drop with timestamp: " + previewMap.keyAt(i)); final long ident = Binder.clearCallingIdentity(); @@ -1639,7 +1652,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } private static List<CaptureBundle> initializeParcelable( - HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap) { + HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap, Integer jpegOrientation, + Byte jpegQuality) { ArrayList<CaptureBundle> ret = new ArrayList<>(); for (Integer stagetId : captureMap.keySet()) { Pair<Image, TotalCaptureResult> entry = captureMap.get(stagetId); @@ -1648,6 +1662,12 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { bundle.captureImage = initializeParcelImage(entry.first); bundle.sequenceId = entry.second.getSequenceId(); bundle.captureResult = entry.second.getNativeMetadata(); + if (jpegOrientation != null) { + bundle.captureResult.set(CaptureResult.JPEG_ORIENTATION, jpegOrientation); + } + if (jpegQuality != null) { + bundle.captureResult.set(CaptureResult.JPEG_QUALITY, jpegQuality); + } ret.add(bundle); } diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java index 9457d8f1aac4..41126b70c89f 100644 --- a/core/java/android/hardware/display/DeviceProductInfo.java +++ b/core/java/android/hardware/display/DeviceProductInfo.java @@ -16,69 +16,40 @@ package android.hardware.display; -import android.annotation.IntDef; -import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Objects; /** * Product-specific information about the display or the directly connected device on the * display chain. For example, if the display is transitively connected, this field may contain * product information about the intermediate device. + * @hide */ public final class DeviceProductInfo implements Parcelable { - /** @hide */ - @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = { - CONNECTION_TO_SINK_UNKNOWN, - CONNECTION_TO_SINK_BUILT_IN, - CONNECTION_TO_SINK_DIRECT, - CONNECTION_TO_SINK_TRANSITIVE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ConnectionToSinkType { } - - /** The device connection to the display sink is unknown. */ - public static final int CONNECTION_TO_SINK_UNKNOWN = - IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN; - - /** The display sink is built-in to the device */ - public static final int CONNECTION_TO_SINK_BUILT_IN = - IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN; - - /** The device is directly connected to the display sink. */ - public static final int CONNECTION_TO_SINK_DIRECT = - IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT; - - /** The device is transitively connected to the display sink. */ - public static final int CONNECTION_TO_SINK_TRANSITIVE = - IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE; - private final String mName; private final String mManufacturerPnpId; private final String mProductId; private final Integer mModelYear; private final ManufactureDate mManufactureDate; - private final @ConnectionToSinkType int mConnectionToSinkType; + private final int[] mRelativeAddress; - /** @hide */ public DeviceProductInfo( String name, String manufacturerPnpId, String productId, Integer modelYear, ManufactureDate manufactureDate, - int connectionToSinkType) { + int[] relativeAddress) { this.mName = name; this.mManufacturerPnpId = manufacturerPnpId; this.mProductId = productId; this.mModelYear = modelYear; this.mManufactureDate = manufactureDate; - this.mConnectionToSinkType = connectionToSinkType; + this.mRelativeAddress = relativeAddress; } private DeviceProductInfo(Parcel in) { @@ -87,13 +58,12 @@ public final class DeviceProductInfo implements Parcelable { mProductId = (String) in.readValue(null); mModelYear = (Integer) in.readValue(null); mManufactureDate = (ManufactureDate) in.readValue(null); - mConnectionToSinkType = in.readInt(); + mRelativeAddress = in.createIntArray(); } /** * @return Display name. */ - @Nullable public String getName() { return mName; } @@ -101,7 +71,6 @@ public final class DeviceProductInfo implements Parcelable { /** * @return Manufacturer Plug and Play ID. */ - @NonNull public String getManufacturerPnpId() { return mManufacturerPnpId; } @@ -109,58 +78,32 @@ public final class DeviceProductInfo implements Parcelable { /** * @return Manufacturer product ID. */ - @NonNull public String getProductId() { return mProductId; } /** - * @return Model year of the device. Return -1 if not available. Typically, - * one of model year or manufacture year is available. + * @return Model year of the device. Typically exactly one of model year or + * manufacture date will be present. */ - public int getModelYear() { - return mModelYear != null ? mModelYear : -1; - } - - /** - * @return The year of manufacture, or -1 it is not available. Typically, - * one of model year or manufacture year is available. - */ - public int getManufactureYear() { - if (mManufactureDate == null) { - return -1; - } - return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1; - } - - /** - * @return The week of manufacture, or -1 it is not available. Typically, - * not present if model year is available. - */ - public int getManufactureWeek() { - if (mManufactureDate == null) { - return -1; - } - return mManufactureDate.mWeek != null ? mManufactureDate.mWeek : -1; + public Integer getModelYear() { + return mModelYear; } /** * @return Manufacture date. Typically exactly one of model year or manufacture * date will be present. - * - * @hide */ public ManufactureDate getManufactureDate() { return mManufactureDate; } /** - * @return How the current device is connected to the display sink. For example, the display - * can be connected immediately to the device or there can be a receiver in between. + * @return Relative address in the display network. For example, for HDMI connected devices this + * can be its physical address. Each component of the address is in the range [0, 255]. */ - @ConnectionToSinkType - public int getConnectionToSinkType() { - return mConnectionToSinkType; + public int[] getRelativeAddress() { + return mRelativeAddress; } @Override @@ -176,8 +119,8 @@ public final class DeviceProductInfo implements Parcelable { + mModelYear + ", manufactureDate=" + mManufactureDate - + ", connectionToSinkType=" - + mConnectionToSinkType + + ", relativeAddress=" + + Arrays.toString(mRelativeAddress) + '}'; } @@ -191,16 +134,16 @@ public final class DeviceProductInfo implements Parcelable { && Objects.equals(mProductId, that.mProductId) && Objects.equals(mModelYear, that.mModelYear) && Objects.equals(mManufactureDate, that.mManufactureDate) - && mConnectionToSinkType == that.mConnectionToSinkType; + && Arrays.equals(mRelativeAddress, that.mRelativeAddress); } @Override public int hashCode() { return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate, - mConnectionToSinkType); + Arrays.hashCode(mRelativeAddress)); } - @NonNull public static final Creator<DeviceProductInfo> CREATOR = + public static final Creator<DeviceProductInfo> CREATOR = new Creator<DeviceProductInfo>() { @Override public DeviceProductInfo createFromParcel(Parcel in) { @@ -219,13 +162,13 @@ public final class DeviceProductInfo implements Parcelable { } @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { + public void writeToParcel(Parcel dest, int flags) { dest.writeString(mName); dest.writeString(mManufacturerPnpId); dest.writeValue(mProductId); dest.writeValue(mModelYear); dest.writeValue(mManufactureDate); - dest.writeInt(mConnectionToSinkType); + dest.writeIntArray(mRelativeAddress); } /** diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index a9bcdeff7e47..f66ecdfb79c3 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -831,6 +831,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan case BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: return context.getString( com.android.internal.R.string.face_error_security_update_required); + case BIOMETRIC_ERROR_RE_ENROLL: + return context.getString( + com.android.internal.R.string.face_recalibrate_notification_content); case FACE_ERROR_VENDOR: { String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.face_error_vendor); diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS index 25e02e1aa6f3..c390b33fa174 100644 --- a/core/java/android/hardware/input/OWNERS +++ b/core/java/android/hardware/input/OWNERS @@ -1,6 +1,3 @@ # Bug component: 136048 include /services/core/java/com/android/server/input/OWNERS - -michaelwr@google.com -svv@google.com diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index 79f9e6ef2a97..dbb312720373 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -15,9 +15,6 @@ */ package android.net; -import static android.Manifest.permission.NETWORK_STACK; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; - import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -26,8 +23,7 @@ import android.content.Context; import android.os.IBinder; import android.os.ServiceManager; -import java.util.ArrayList; -import java.util.Arrays; +import com.android.net.module.util.PermissionUtils; /** * Constants and utilities for client code communicating with the network stack service. * @hide @@ -79,9 +75,14 @@ public class NetworkStack { * @param context {@link android.content.Context} for the process. * * @hide + * + * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermission} instead. + * + * TODO: remove this method and let the users call to PermissionUtils directly. */ + @Deprecated public static void checkNetworkStackPermission(final @NonNull Context context) { - checkNetworkStackPermissionOr(context); + PermissionUtils.enforceNetworkStackPermission(context); } /** @@ -92,31 +93,14 @@ public class NetworkStack { * @param otherPermissions The set of permissions that could be the candidate permissions , or * empty string if none of other permissions needed. * @hide + * + * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermissionOr} instead. + * + * TODO: remove this method and let the users call to PermissionUtils directly. */ + @Deprecated public static void checkNetworkStackPermissionOr(final @NonNull Context context, final @NonNull String... otherPermissions) { - ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions)); - permissions.add(NETWORK_STACK); - permissions.add(PERMISSION_MAINLINE_NETWORK_STACK); - enforceAnyPermissionOf(context, permissions.toArray(new String[0])); + PermissionUtils.enforceNetworkStackPermissionOr(context, otherPermissions); } - - private static void enforceAnyPermissionOf(final @NonNull Context context, - final @NonNull String... permissions) { - if (!checkAnyPermissionOf(context, permissions)) { - throw new SecurityException("Requires one of the following permissions: " - + String.join(", ", permissions) + "."); - } - } - - private static boolean checkAnyPermissionOf(final @NonNull Context context, - final @NonNull String... permissions) { - for (String permission : permissions) { - if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { - return true; - } - } - return false; - } - } diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java index 49047d3a0c87..8f6510ed3ea5 100644 --- a/core/java/android/net/NetworkWatchlistManager.java +++ b/core/java/android/net/NetworkWatchlistManager.java @@ -16,6 +16,8 @@ package android.net; +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -29,6 +31,7 @@ import com.android.internal.util.Preconditions; * Class that manage network watchlist in system. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.NETWORK_WATCHLIST_SERVICE) public class NetworkWatchlistManager { @@ -90,6 +93,7 @@ public class NetworkWatchlistManager { /** * Get Network Watchlist config file hash. */ + @Nullable public byte[] getWatchlistConfigHash() { try { return mNetworkWatchlistManager.getWatchlistConfigHash(); diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index b172ccc4e370..f0e7da78d669 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -42,10 +42,6 @@ public final class UidRange implements Parcelable { stop = stopUid; } - public static UidRange createForUser(int userId) { - return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); - } - /** Creates a UidRange for the specified user. */ public static UidRange createForUser(UserHandle user) { final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1); diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index e43b0b6fa635..f90fbaf1e0fb 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -596,7 +596,8 @@ public class VpnService extends Service { } } } - mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null)); + mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null, + RouteInfo.RTN_UNICAST)); mConfig.updateAllowedFamilies(address); return this; } diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl index 555e9b5883e8..d91cef592d10 100644 --- a/core/java/android/net/vcn/IVcnStatusCallback.aidl +++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl @@ -17,8 +17,9 @@ package android.net.vcn; /** @hide */ -interface IVcnStatusCallback { +oneway interface IVcnStatusCallback { void onEnteredSafeMode(); + void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, int errorCode, diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index aea0ea988f50..eb8c251fec78 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.net.LinkProperties; @@ -72,8 +73,7 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map< - VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +93,13 @@ public class VcnManager { } /** - * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map<VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -161,45 +161,126 @@ public class VcnManager { } } - // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi + // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using + // the new VcnNetworkPolicyListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener { + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} + + /** + * Add a listener for VCN-underlying network policy updates. + * + * @param executor the Executor that will be used for invoking all calls to the specified + * Listener + * @param listener the VcnUnderlyingNetworkPolicyListener to be added + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already + * registered + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void addVcnUnderlyingNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { + addVcnNetworkPolicyListener(executor, listener); + } + + /** + * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager. + * + * <p>If the specified listener is not currently registered, this is a no-op. + * + * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed + * @hide + */ + public void removeVcnUnderlyingNetworkPolicyListener( + @NonNull VcnUnderlyingNetworkPolicyListener listener) { + removeVcnNetworkPolicyListener(listener); + } + + /** + * Queries the underlying network policy for a network with the given parameters. + * + * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy + * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network + * Provider MUST poll for the updated Network policy based on that Network's capabilities and + * properties. + * + * @param networkCapabilities the NetworkCapabilities to be used in determining the Network + * policy for this Network. + * @param linkProperties the LinkProperties to be used in determining the Network policy for + * this Network. + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @return the VcnUnderlyingNetworkPolicy to be used for this Network. + * @hide + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy( + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties) { + requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + requireNonNull(linkProperties, "linkProperties must not be null"); + + try { + return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * VcnNetworkPolicyListener is the interface through which internal system components (e.g. + * Network Factories) can register to receive updates for VCN-underlying Network policies from + * the System Server. + * + * <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks + * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify + * the registrant when VCN Network policies change. Upon receiving this signal, the listener + * must check {@link VcnManager} for the current Network policy result for each of its Networks + * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * + * @hide + */ + @SystemApi + public interface VcnNetworkPolicyListener { /** * Notifies the implementation that the VCN's underlying Network policy has changed. * - * <p>After receiving this callback, implementations MUST poll VcnManager for the updated - * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy. + * <p>After receiving this callback, implementations should get the current {@link + * VcnNetworkPolicyResult} via {@link #applyVcnNetworkPolicy(NetworkCapabilities, + * LinkProperties)}. */ void onPolicyChanged(); } /** - * Add a listener for VCN-underlying network policy updates. + * Add a listener for VCN-underlying Network policy updates. + * + * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is + * registered. No callbacks are guaranteed upon registration. * * @param executor the Executor that will be used for invoking all calls to the specified * Listener - * @param listener the VcnUnderlyingNetworkPolicyListener to be added + * @param listener the VcnNetworkPolicyListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is - * already registered + * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public void addVcnUnderlyingNetworkPolicyListener( - @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { + public void addVcnNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { requireNonNull(executor, "executor must not be null"); requireNonNull(listener, "listener must not be null"); VcnUnderlyingNetworkPolicyListenerBinder binder = new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { - throw new IllegalArgumentException( - "Attempting to add a listener that is already in use"); + throw new IllegalStateException("listener is already registered with VcnManager"); } try { @@ -211,15 +292,15 @@ public class VcnManager { } /** - * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager. + * Remove the specified VcnNetworkPolicyListener from VcnManager. * * <p>If the specified listener is not currently registered, this is a no-op. * - * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed + * @param listener the VcnNetworkPolicyListener that will be removed * @hide */ - public void removeVcnUnderlyingNetworkPolicyListener( - @NonNull VcnUnderlyingNetworkPolicyListener listener) { + @SystemApi + public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { requireNonNull(listener, "listener must not be null"); VcnUnderlyingNetworkPolicyListenerBinder binder = @@ -236,39 +317,88 @@ public class VcnManager { } /** - * Queries the underlying network policy for a network with the given parameters. + * Applies the network policy for a {@link android.net.Network} with the given parameters. * * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy - * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network - * Provider MUST poll for the updated Network policy based on that Network's capabilities and - * properties. + * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider + * MUST poll for the updated Network policy based on that Network's capabilities and properties. * * @param networkCapabilities the NetworkCapabilities to be used in determining the Network - * policy for this Network. - * @param linkProperties the LinkProperties to be used in determining the Network policy for - * this Network. + * policy result for this Network. + * @param linkProperties the LinkProperties to be used in determining the Network policy result + * for this Network. * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @return the VcnUnderlyingNetworkPolicy to be used for this Network. + * @return the {@link VcnNetworkPolicyResult} to be used for this Network. * @hide */ @NonNull + @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy( + public VcnNetworkPolicyResult applyVcnNetworkPolicy( @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties) { requireNonNull(networkCapabilities, "networkCapabilities must not be null"); requireNonNull(linkProperties, "linkProperties must not be null"); - try { - return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + final VcnUnderlyingNetworkPolicy policy = + getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); + return new VcnNetworkPolicyResult( + policy.isTeardownRequested(), policy.getMergedNetworkCapabilities()); } /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ + VCN_STATUS_CODE_NOT_CONFIGURED, + VCN_STATUS_CODE_INACTIVE, + VCN_STATUS_CODE_ACTIVE, + VCN_STATUS_CODE_SAFE_MODE + }) + public @interface VcnStatusCode {} + + /** + * Value indicating that the VCN for the subscription group is not configured, or that the + * callback is not privileged for the subscription group. + * + * @hide + */ + public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; + + /** + * Value indicating that the VCN for the subscription group is inactive. + * + * <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the + * provisioning package is not privileged. + * + * @hide + */ + public static final int VCN_STATUS_CODE_INACTIVE = 1; + + /** + * Value indicating that the VCN for the subscription group is active. + * + * <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning + * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered + * active while it is connecting, fully connected, and disconnecting. + * + * @hide + */ + public static final int VCN_STATUS_CODE_ACTIVE = 2; + + /** + * Value indicating that the VCN for the subscription group is in Safe Mode. + * + * <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to + * establish a connection within a system-determined timeout (while underlying networks were + * available). + * + * @hide + */ + public static final int VCN_STATUS_CODE_SAFE_MODE = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ VCN_ERROR_CODE_INTERNAL_ERROR, VCN_ERROR_CODE_CONFIG_ERROR, VCN_ERROR_CODE_NETWORK_ERROR @@ -323,8 +453,18 @@ public class VcnManager { * * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. + * + * @hide */ - public abstract void onEnteredSafeMode(); + public void onEnteredSafeMode() {} + + /** + * Invoked when status of the VCN for this callback's subscription group changes. + * + * @param statusCode the code for the status change encountered by this {@link + * VcnStatusCallback}'s subscription group. + */ + public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** * Invoked when a VCN Gateway Connection corresponding to this callback's subscription @@ -356,6 +496,11 @@ public class VcnManager { * <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the + * current status for the specified subscription group's VCN. If the registrant is not + * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be + * returned. + * * @param subscriptionGroup The subscription group to match for callbacks * @param executor The {@link Executor} to be used for invoking callbacks * @param callback The VcnStatusCallback to be registered @@ -415,18 +560,17 @@ public class VcnManager { } /** - * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System - * Server. + * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnUnderlyingNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnUnderlyingNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyListener listener) { mExecutor = executor; mListener = listener; } @@ -460,6 +604,12 @@ public class VcnManager { () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); } + @Override + public void onVcnStatusChanged(@VcnStatusCode int statusCode) { + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); + } + // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' @Override public void onGatewayConnectionError( diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl new file mode 100644 index 000000000000..3f13abe869da --- /dev/null +++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl @@ -0,0 +1,20 @@ +/* + * 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.vcn; + +/** @hide */ +parcelable VcnNetworkPolicyResult; diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java new file mode 100644 index 000000000000..5e938200639c --- /dev/null +++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java @@ -0,0 +1,114 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.NetworkCapabilities; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its + * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * + * <p>Bearers that are bringing up networks capable of acting as a VCN's underlying network should + * query for Network policy results upon any capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via {@link VcnManager.VcnNetworkPolicyListener}. + * + * @hide + */ +@SystemApi +public final class VcnNetworkPolicyResult implements Parcelable { + private final boolean mIsTearDownRequested; + private final NetworkCapabilities mNetworkCapabilities; + + /** + * Constructs a VcnNetworkPolicyResult with the specified parameters. + * + * @hide + */ + public VcnNetworkPolicyResult( + boolean isTearDownRequested, @NonNull NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(networkCapabilities, "networkCapabilities must be non-null"); + + mIsTearDownRequested = isTearDownRequested; + mNetworkCapabilities = networkCapabilities; + } + + /** + * Returns whether this VCN policy result requires that the underlying Network should be torn + * down. + * + * <p>Upon querying for the current Network policy result, the bearer must check this method, + * and MUST tear down the corresponding Network if it returns true. + */ + public boolean isTeardownRequested() { + return mIsTearDownRequested; + } + + /** + * Returns the NetworkCapabilities that the bearer should be using for the corresponding + * Network. + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + @Override + public int hashCode() { + return Objects.hash(mIsTearDownRequested, mNetworkCapabilities); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VcnNetworkPolicyResult)) return false; + final VcnNetworkPolicyResult that = (VcnNetworkPolicyResult) o; + + return mIsTearDownRequested == that.mIsTearDownRequested + && mNetworkCapabilities.equals(that.mNetworkCapabilities); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsTearDownRequested); + dest.writeParcelable(mNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator<VcnNetworkPolicyResult> CREATOR = + new Creator<VcnNetworkPolicyResult>() { + public VcnNetworkPolicyResult createFromParcel(Parcel in) { + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); + } + + public VcnNetworkPolicyResult[] newArray(int size) { + return new VcnNetworkPolicyResult[size]; + } + }; +} diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java index dd7c86d87ff2..b47d5642419e 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -33,8 +33,7 @@ import java.util.Objects; * @hide */ public final class VcnUnderlyingNetworkPolicy implements Parcelable { - private final boolean mIsTearDownRequested; - private final NetworkCapabilities mMergedNetworkCapabilities; + private final VcnNetworkPolicyResult mVcnNetworkPolicyResult; /** * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters. @@ -46,8 +45,13 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { Objects.requireNonNull( mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull"); - mIsTearDownRequested = isTearDownRequested; - mMergedNetworkCapabilities = mergedNetworkCapabilities; + mVcnNetworkPolicyResult = + new VcnNetworkPolicyResult(isTearDownRequested, mergedNetworkCapabilities); + } + + private VcnUnderlyingNetworkPolicy(@NonNull VcnNetworkPolicyResult vcnNetworkPolicyResult) { + this.mVcnNetworkPolicyResult = + Objects.requireNonNull(vcnNetworkPolicyResult, "vcnNetworkPolicyResult"); } /** @@ -55,7 +59,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { * be torn down. */ public boolean isTeardownRequested() { - return mIsTearDownRequested; + return mVcnNetworkPolicyResult.isTeardownRequested(); } /** @@ -64,12 +68,12 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { */ @NonNull public NetworkCapabilities getMergedNetworkCapabilities() { - return mMergedNetworkCapabilities; + return mVcnNetworkPolicyResult.getNetworkCapabilities(); } @Override public int hashCode() { - return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities); + return Objects.hash(mVcnNetworkPolicyResult); } @Override @@ -78,8 +82,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false; final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o; - return mIsTearDownRequested == that.mIsTearDownRequested - && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities); + return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult); } /** {@inheritDoc} */ @@ -91,16 +94,14 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { /** {@inheritDoc} */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeBoolean(mIsTearDownRequested); - dest.writeParcelable(mMergedNetworkCapabilities, flags); + dest.writeParcelable(mVcnNetworkPolicyResult, flags); } /** Implement the Parcelable interface */ public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR = new Creator<VcnUnderlyingNetworkPolicy>() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy( - in.readBoolean(), in.readParcelable(null)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 305c686f8657..a435ac12d33c 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.WorkerThread; import android.app.ActivityManager; import android.content.Context; import android.util.Log; @@ -41,7 +42,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; -/** Class that provides a privileged API to capture and consume bugreports. */ +/** + * Class that provides a privileged API to capture and consume bugreports. + * + * <p>This class may only be used by apps that currently have carrier privileges (see {@link + * android.telephony.TelephonyManager#hasCarrierPrivileges}) on an active SIM or priv-apps + * explicitly allowed by the device manufacturer. + * + * <p>Only one bugreport can be generated by the system at a time. + */ @SystemService(Context.BUGREPORT_SERVICE) public final class BugreportManager { @@ -56,7 +65,12 @@ public final class BugreportManager { mBinder = binder; } - /** An interface describing the callback for bugreport progress and status. */ + /** + * An interface describing the callback for bugreport progress and status. + * + * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport + * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}. + */ public abstract static class BugreportCallback { /** * Possible error codes taking a bugreport can encounter. @@ -75,15 +89,18 @@ public final class BugreportManager { }) public @interface BugreportErrorCode {} - /** The input options were invalid */ + /** + * The input options were invalid. For example, the destination file the app provided could + * not be written by the system. + */ public static final int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT; - /** A runtime error occurred */ + /** A runtime error occurred. */ public static final int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR; - /** User denied consent to share the bugreport */ + /** User denied consent to share the bugreport. */ public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT; @@ -149,6 +166,7 @@ public final class BugreportManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.DUMP) + @WorkerThread public void startBugreport( @NonNull ParcelFileDescriptor bugreportFd, @Nullable ParcelFileDescriptor screenshotFd, @@ -222,6 +240,7 @@ public final class BugreportManager { * @param callback callback for progress and status updates. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @WorkerThread public void startConnectivityBugreport( @NonNull ParcelFileDescriptor bugreportFd, @NonNull @CallbackExecutor Executor executor, @@ -247,6 +266,7 @@ public final class BugreportManager { * @throws SecurityException if trying to cancel another app's bugreport in progress */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @WorkerThread public void cancelBugreport() { try { mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName()); diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 93c1690e3813..43184ea4b9a9 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -26,6 +26,7 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.app.KeyguardManager; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -631,10 +632,15 @@ public class RecoverySystem { /** * Prepare to apply an unattended update by asking the user for their Lock Screen Knowledge * Factor (LSKF). If supplied, the {@code intentSender} will be called when the system is setup - * and ready to apply the OTA. This API is expected to handle requests from multiple clients - * simultaneously, e.g. from ota and mainline. + * and ready to apply the OTA. <p> * - * <p> The behavior of multi-client Resume on Reboot works as follows + * <p> If the device doesn't setup a lock screen, i.e. by checking + * {@link KeyguardManager#isKeyguardSecure()}, this API call will fail and throw an exception. + * Callers are expected to use {@link PowerManager#reboot(String)} directly without going + * through the RoR flow. <p> + * + * <p> This API is expected to handle requests from multiple clients simultaneously, e.g. + * from ota and mainline. The behavior of multi-client Resume on Reboot works as follows * <li> Each client should call this function to prepare for Resume on Reboot before calling * {@link #rebootAndApply(Context, String, boolean)} </li> * <li> One client cannot clear the Resume on Reboot preparation of another client. </li> @@ -658,6 +664,13 @@ public class RecoverySystem { if (updateToken == null) { throw new NullPointerException("updateToken == null"); } + + KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class); + if (keyguardManager == null || !keyguardManager.isDeviceSecure()) { + throw new IOException("Failed to request LSKF because the device doesn't have a" + + " lock screen. "); + } + RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE); if (!rs.requestLskf(context.getPackageName(), intentSender)) { throw new IOException("preparation for update failed"); diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index d6fa733927fb..b003d238c268 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -186,7 +186,8 @@ public abstract class Vibrator { /** * Return the ID of this vibrator. * - * @return The id of the vibrator controlled by this service. + * @return A non-negative integer representing the id of the vibrator controlled by this + * service, or -1 this service is not attached to any physical vibrator. */ public int getId() { return -1; diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java index 5dd38b6cbd86..5a01814508e1 100644 --- a/core/java/android/os/VibratorManager.java +++ b/core/java/android/os/VibratorManager.java @@ -91,10 +91,10 @@ public abstract class VibratorManager { * * <p> * Pass in a {@link CombinedVibrationEffect} representing a combination of {@link - * VibrationEffect} to be played on one or more vibrators. + * VibrationEffect VibrationEffects} to be played on one or more vibrators. * </p> * - * @param effect an array of longs of times for which to turn the vibrator on or off. + * @param effect a combination of effects to be performed by one or more vibrators. */ @RequiresPermission(android.Manifest.permission.VIBRATE) public final void vibrate(@NonNull CombinedVibrationEffect effect) { @@ -109,7 +109,7 @@ public abstract class VibratorManager { * VibrationEffect} to be played on one or more vibrators. * </p> * - * @param effect an array of longs of times for which to turn the vibrator on or off. + * @param effect a combination of effects to be performed by one or more vibrators. * @param attributes {@link VibrationAttributes} corresponding to the vibration. For example, * specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or * {@link VibrationAttributes#USAGE_RINGTONE} for vibrations associated with diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index e134c29520b2..4354920c83ec 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -275,6 +275,14 @@ public final class DeviceConfig { public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot"; /** + * Namespace for features related to Reboot Readiness detection. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness"; + + /** * Namespace for Rollback flags that are applied immediately. * * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ff10b0caab89..d50dc7fc882d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14606,29 +14606,6 @@ public final class Settings { public static final String POWER_BUTTON_VERY_LONG_PRESS = "power_button_very_long_press"; - - /** - * Keyguard should be on the left hand side of the screen, for wide screen layouts. - * - * @hide - */ - public static final int ONE_HANDED_KEYGUARD_SIDE_LEFT = 0; - - /** - * Keyguard should be on the right hand side of the screen, for wide screen layouts. - * - * @hide - */ - public static final int ONE_HANDED_KEYGUARD_SIDE_RIGHT = 1; - /** - * In one handed mode, which side the keyguard should be on. Allowable values are one of - * the ONE_HANDED_KEYGUARD_SIDE_* constants. - * - * @hide - */ - @Readable - public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side"; - /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java index 074d5f167ec3..030b86339822 100644 --- a/core/java/android/provider/SimPhonebookContract.java +++ b/core/java/android/provider/SimPhonebookContract.java @@ -44,8 +44,11 @@ import java.util.Objects; * The contract between the provider of contact records on the device's SIM cards and applications. * Contains definitions of the supported URIs and columns. * - * <p>This content provider does not support any of the QUERY_ARG_SQL* bundle arguments. An - * IllegalArgumentException will be thrown if these are included. + * <h3>Permissions</h3> + * <p> + * Querying this provider requires {@link android.Manifest.permission#READ_CONTACTS} and writing + * to this provider requires {@link android.Manifest.permission#WRITE_CONTACTS} + * </p> */ public final class SimPhonebookContract { @@ -85,7 +88,73 @@ public final class SimPhonebookContract { } } - /** Constants for the contact records on a SIM card. */ + /** + * Constants for the contact records on a SIM card. + * + * <h3 id="simrecords-data">Data</h3> + * <p> + * Data is stored in a specific elementary file on a specific SIM card and these are isolated + * from each other. SIM cards are identified by their subscription ID. SIM cards may not support + * all or even any of the elementary file types. A SIM will have constraints on + * the values of the data that can be stored in each elementary file. The available SIMs, + * their supported elementary file types and the constraints on the data can be discovered by + * querying {@link ElementaryFiles#CONTENT_URI}. Each elementary file has a fixed capacity + * for the number of records that may be stored. This can be determined from the value + * of the {@link ElementaryFiles#MAX_RECORDS} column. + * </p> + * <p> + * The {@link SimRecords#PHONE_NUMBER} column can only contain dialable characters and this + * applies regardless of the SIM that is being used. See + * {@link android.telephony.PhoneNumberUtils#isDialable(char)} for more details. Additionally + * the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH} + * characters. The {@link SimRecords#NAME} column can contain at most + * {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM. + * Encoding is done internally and so the name should be provided unencoded but the number of + * bytes required to encode it will vary depending on the characters it contains. This length + * can be determined by calling + * {@link SimRecords#getEncodedNameLength(ContentResolver, String)}. + * </p> + * <h3>Operations </h3> + * <dl> + * <dd><b>Insert</b></dd> + * <p> + * Only {@link ElementaryFiles#EF_ADN} supports inserts. {@link SimRecords#PHONE_NUMBER} + * is a required column. If the value provided for this column is missing, null, empty + * or violates the requirements discussed in the <a href="#simrecords-data">Data</a> + * section above an {@link IllegalArgumentException} will be thrown. The + * {@link SimRecords#NAME} column may be omitted but if provided and it violates any of + * the requirements discussed in the <a href="#simrecords-data">Data</a> section above + * an {@link IllegalArgumentException} will be thrown. + * </p> + * <p> + * If an insert is not possible because the elementary file is full then an + * {@link IllegalStateException} will be thrown. + * </p> + * <dd><b>Update</b></dd> + * <p> + * Updates can only be performed for individual records on {@link ElementaryFiles#EF_ADN}. + * A specific record is referenced via the Uri returned by + * {@link SimRecords#getItemUri(int, int, int)}. Updates have the same constraints and + * behavior for the {@link SimRecords#PHONE_NUMBER} and {@link SimRecords#NAME} as insert. + * However, in the case of update the {@link SimRecords#PHONE_NUMBER} may be omitted as + * the existing record will already have a valid value. + * </p> + * <dd><b>Delete</b></dd> + * <p> + * Delete may only be performed for individual records on {@link ElementaryFiles#EF_ADN}. + * Deleting records will free up space for use by future inserts. + * </p> + * <dd><b>Query</b></dd> + * <p> + * All the records stored on a specific elementary file can be read via a Uri returned by + * {@link SimRecords#getContentUri(int, int)}. This query always returns all records; there + * is no support for filtering via a selection. An individual record can be queried via a Uri + * returned by {@link SimRecords#getItemUri(int, int, int)}. Queries will throw an + * {@link IllegalArgumentException} when the SIM with the subscription ID or the elementary file + * type are invalid or unavailable. + * </p> + * </dl> + */ public static final class SimRecords { /** @@ -197,8 +266,8 @@ public final class SimPhonebookContract { * be discovered by querying {@link ElementaryFiles#CONTENT_URI}. * * <p>If a SIM with the provided subscription ID does not exist or the SIM with the provided - * subscription ID doesn't support the specified entity file then queries will return - * and empty cursor and inserts will throw an {@link IllegalArgumentException} + * subscription ID doesn't support the specified entity file then all operations will + * throw an {@link IllegalArgumentException}. * * @param subscriptionId the subscriptionId of the SIM card that this Uri will reference * @param efType the elementary file on the SIM that this Uri will reference @@ -233,6 +302,9 @@ public final class SimPhonebookContract { * must be greater than 0. If there is no record with this record * number in the specified entity file then it will be treated as a * non-existent record. + * @see ElementaryFiles#SUBSCRIPTION_ID + * @see ElementaryFiles#EF_TYPE + * @see #RECORD_NUMBER */ @NonNull public static Uri getItemUri( @@ -287,7 +359,28 @@ public final class SimPhonebookContract { } - /** Constants for metadata about the elementary files of the SIM cards in the phone. */ + /** + * Constants for metadata about the elementary files of the SIM cards in the phone. + * + * <h3>Operations </h3> + * <dl> + * <dd><b>Insert</b></dd> + * <p>Insert is not supported for the Uris defined in this class.</p> + * <dd><b>Update</b></dd> + * <p>Update is not supported for the Uris defined in this class.</p> + * <dd><b>Delete</b></dd> + * <p>Delete is not supported for the Uris defined in this class.</p> + * <dd><b>Query</b></dd> + * <p> + * The elementary files for all the inserted SIMs can be read via + * {@link ElementaryFiles#CONTENT_URI}. Unsupported elementary files are omitted from the + * results. This Uri always returns all supported elementary files for all available SIMs; it + * does not support filtering via a selection. A specific elementary file can be queried + * via a Uri returned by {@link ElementaryFiles#getItemUri(int, int)}. If the elementary file + * referenced by this Uri is unsupported by the SIM then the query will return an empty cursor. + * </p> + * </dl> + */ public static final class ElementaryFiles { /** {@link SubscriptionInfo#getSimSlotIndex()} of the SIM for this row. */ diff --git a/core/java/android/uwb/AngleOfArrivalSupport.aidl b/core/java/android/uwb/AngleOfArrivalSupport.aidl deleted file mode 100644 index 57666ff8bca9..000000000000 --- a/core/java/android/uwb/AngleOfArrivalSupport.aidl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -/** - * @hide - */ -@Backing(type="int") -enum AngleOfArrivalSupport { - /** - * The device does not support angle of arrival - */ - NONE, - - /** - * The device supports planar angle of arrival - */ - TWO_DIMENSIONAL, - - /** - * The device does supports three dimensional angle of arrival with hemispherical azimuth angles - */ - THREE_DIMENSIONAL_HEMISPHERICAL, - - /** - * The device does supports three dimensional angle of arrival with full azimuth angles - */ - THREE_DIMENSIONAL_SPHERICAL, -} - diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl index b9c55081a103..468a69c7bddb 100644 --- a/core/java/android/uwb/IUwbAdapter.aidl +++ b/core/java/android/uwb/IUwbAdapter.aidl @@ -17,7 +17,6 @@ package android.uwb; import android.os.PersistableBundle; -import android.uwb.AngleOfArrivalSupport; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbRangingCallbacks; import android.uwb.SessionHandle; @@ -47,43 +46,6 @@ interface IUwbAdapter { void unregisterAdapterStateCallbacks(in IUwbAdapterStateCallbacks callbacks); /** - * Returns true if ranging is supported, false otherwise - */ - boolean isRangingSupported(); - - /** - * Get the angle of arrival supported by this device - * - * @return the angle of arrival type supported - */ - AngleOfArrivalSupport getAngleOfArrivalSupport(); - - /** - * Generates a list of the supported 802.15.4z channels - * - * The list must be prioritized in the order of preferred channel usage. - * - * The list must only contain channels that are permitted to be used in the - * device's current location. - * - * @return an array of support channels on the device for the current location. - */ - int[] getSupportedChannels(); - - /** - * Generates a list of the supported 802.15.4z preamble codes - * - * The list must be prioritized in the order of preferred preamble usage. - * - * The list must only contain preambles that are permitted to be used in the - * device's current location. - * - * @return an array of supported preambles on the device for the current - * location. - */ - int[] getSupportedPreambleCodes(); - - /** * Get the accuracy of the ranging timestamps * * @return accuracy of the ranging timestamps in nanoseconds @@ -91,27 +53,6 @@ interface IUwbAdapter { long getTimestampResolutionNanos(); /** - * Get the supported number of simultaneous ranging sessions - * - * @return the supported number of simultaneous ranging sessions - */ - int getMaxSimultaneousSessions(); - - /** - * Get the maximum number of remote devices per session when local device is initiator - * - * @return the maximum number of remote devices supported in a single session - */ - int getMaxRemoteDevicesPerInitiatorSession(); - - /** - * Get the maximum number of remote devices per session when local device is responder - * - * @return the maximum number of remote devices supported in a single session - */ - int getMaxRemoteDevicesPerResponderSession(); - - /** * Provides the capabilities and features of the device * * @return specification specific capabilities and features of the device diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java index 2dc0ba0b9b80..63a6d058f358 100644 --- a/core/java/android/uwb/UwbManager.java +++ b/core/java/android/uwb/UwbManager.java @@ -32,10 +32,6 @@ import android.os.ServiceManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.concurrent.Executor; /** @@ -195,133 +191,6 @@ public final class UwbManager { } /** - * Check if ranging is supported, regardless of ranging method - * - * @return true if ranging is supported - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public boolean isRangingSupported() { - try { - return mUwbAdapter.isRangingSupported(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}) - public @interface AngleOfArrivalSupportType {} - - /** - * Indicate absence of support for angle of arrival measurement - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; - - /** - * Indicate support for planar angle of arrival measurement, due to antenna - * limitation. Typically requires at least two antennas. - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; - - /** - * Indicate support for three dimensional angle of arrival measurement. - * Typically requires at least three antennas. However, due to antenna - * arrangement, a platform may only support hemi-spherical azimuth angles - * ranging from -pi/2 to pi/2 - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; - - /** - * Indicate support for three dimensional angle of arrival measurement. - * Typically requires at least three antennas. This mode supports full - * azimuth angles ranging from -pi to pi. - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; - - /** - * Gets the {@link AngleOfArrivalSupportType} supported on this platform - * <p>Possible return values are - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}. - * - * @return angle of arrival type supported - */ - @AngleOfArrivalSupportType - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getAngleOfArrivalSupport() { - try { - switch (mUwbAdapter.getAngleOfArrivalSupport()) { - case AngleOfArrivalSupport.TWO_DIMENSIONAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D; - - case AngleOfArrivalSupport.THREE_DIMENSIONAL_HEMISPHERICAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL; - - case AngleOfArrivalSupport.THREE_DIMENSIONAL_SPHERICAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL; - - case AngleOfArrivalSupport.NONE: - default: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get a {@link List} of supported channel numbers based on the device's current location - * <p>The returned values are ordered by the system's desired ordered of use, with the first - * entry being the most preferred. - * - * <p>Channel numbers are defined based on the IEEE 802.15.4z standard for UWB. - * - * @return {@link List} of supported channel numbers ordered by preference - */ - @NonNull - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public List<Integer> getSupportedChannelNumbers() { - List<Integer> channels = new ArrayList<>(); - try { - for (int channel : mUwbAdapter.getSupportedChannels()) { - channels.add(channel); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return channels; - } - - /** - * Get a {@link List} of supported preamble code indices - * <p> Preamble code indices are defined based on the IEEE 802.15.4z standard for UWB. - * - * @return {@link List} of supported preamble code indices - */ - @NonNull - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public Set<Integer> getSupportedPreambleCodeIndices() { - Set<Integer> preambles = new HashSet<>(); - try { - for (int preamble : mUwbAdapter.getSupportedPreambleCodes()) { - preambles.add(preamble); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return preambles; - } - - /** * Get the timestamp resolution for events in nanoseconds * <p>This value defines the maximum error of all timestamps for events reported to * {@link RangingSession.Callback}. @@ -339,50 +208,6 @@ public final class UwbManager { } /** - * Get the number of simultaneous sessions allowed in the system - * - * @return the maximum allowed number of simultaneously open {@link RangingSession} instances. - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxSimultaneousSessions() { - try { - return mUwbAdapter.getMaxSimultaneousSessions(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the maximum number of remote devices in a {@link RangingSession} when the local device - * is the initiator. - * - * @return the maximum number of remote devices per {@link RangingSession} - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxRemoteDevicesPerInitiatorSession() { - try { - return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the maximum number of remote devices in a {@link RangingSession} when the local device - * is a responder. - * - * @return the maximum number of remote devices per {@link RangingSession} - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxRemoteDevicesPerResponderSession() { - try { - return mUwbAdapter.getMaxRemoteDevicesPerResponderSession(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Open a {@link RangingSession} with the given parameters * <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a * {@link RangingSession} object used to control ranging when the session is successfully diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 8117c963b959..0ba1dfee16f3 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -34,7 +34,6 @@ import android.graphics.ColorSpace; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; -import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; @@ -1182,18 +1181,6 @@ public final class Display { } /** - * Returns the product-specific information about the display or the directly connected - * device on the display chain. - * For example, if the display is transitively connected, this field may contain product - * information about the intermediate device. - * Returns {@code null} if product information is not available. - */ - @Nullable - public DeviceProductInfo getDeviceProductInfo() { - return mDisplayInfo.deviceProductInfo; - } - - /** * Gets display metrics that describe the size and density of this display. * The size returned by this method does not necessarily represent the * actual raw size (native resolution) of the display. diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 2bd32acc6c2c..0832578d80c5 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -191,9 +191,6 @@ public final class SurfaceControl implements Parcelable { private static native void nativeReparent(long transactionObj, long nativeObject, long newParentNativeObject); - private static native boolean nativeGetAutoLowLatencyModeSupport(IBinder displayToken); - private static native boolean nativeGetGameContentTypeSupport(IBinder displayToken); - private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject, InputWindowHandle handle); @@ -1750,6 +1747,9 @@ public final class SurfaceControl implements Parcelable { public Display.HdrCapabilities hdrCapabilities; + public boolean autoLowLatencyModeSupported; + public boolean gameContentTypeSupported; + @Override public String toString() { return "DynamicDisplayInfo{" @@ -1757,7 +1757,9 @@ public final class SurfaceControl implements Parcelable { + ", activeDisplayModeId=" + activeDisplayModeId + ", supportedColorModes=" + Arrays.toString(supportedColorModes) + ", activeColorMode=" + activeColorMode - + ", hdrCapabilities=" + hdrCapabilities + "}"; + + ", hdrCapabilities=" + hdrCapabilities + + ", autoLowLatencyModeSupported=" + autoLowLatencyModeSupported + + ", gameContentTypeSupported" + gameContentTypeSupported + "}"; } @Override @@ -2204,28 +2206,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public static boolean getAutoLowLatencyModeSupport(IBinder displayToken) { - if (displayToken == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - return nativeGetAutoLowLatencyModeSupport(displayToken); - } - - /** - * @hide - */ - public static boolean getGameContentTypeSupport(IBinder displayToken) { - if (displayToken == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - return nativeGetGameContentTypeSupport(displayToken); - } - - /** - * @hide - */ @UnsupportedAppUsage public static IBinder createDisplay(String name, boolean secure) { if (name == null) { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 05b177ebbb45..39c09b46f2e1 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6612,6 +6612,27 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** + * Returns the {@link EdgeEffect#getType()} for the edge effects. + * @return the {@link EdgeEffect#getType()} for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + @EdgeEffect.EdgeEffectType + public int getEdgeEffectType() { + return mEdgeGlowTop.getType(); + } + + /** + * Sets the {@link EdgeEffect#setType(int)} for the edge effects. + * @param type The edge effect type to use for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { + mEdgeGlowTop.setType(type); + mEdgeGlowBottom.setType(type); + invalidate(); + } + + /** * Sets the recycler listener to be notified whenever a View is set aside in * the recycler for later reuse. This listener can be used to free resources * associated to the View. diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 93b2d8ae3c9a..34fe51e82e8f 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -23,8 +23,10 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; @@ -68,12 +70,16 @@ public class AnalogClock extends View { @UnsupportedAppUsage private Drawable mHourHand; + private final TintInfo mHourHandTintInfo = new TintInfo(); @UnsupportedAppUsage private Drawable mMinuteHand; + private final TintInfo mMinuteHandTintInfo = new TintInfo(); @Nullable private Drawable mSecondHand; + private final TintInfo mSecondHandTintInfo = new TintInfo(); @UnsupportedAppUsage private Drawable mDial; + private final TintInfo mDialTintInfo = new TintInfo(); private int mDialWidth; private int mDialHeight; @@ -111,18 +117,86 @@ public class AnalogClock extends View { mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial); } + ColorStateList dialTintList = a.getColorStateList( + com.android.internal.R.styleable.AnalogClock_dialTint); + if (dialTintList != null) { + mDialTintInfo.mTintList = dialTintList; + mDialTintInfo.mHasTintList = true; + } + BlendMode dialTintMode = Drawable.parseBlendMode( + a.getInt(com.android.internal.R.styleable.AnalogClock_dialTintMode, -1), + null); + if (dialTintMode != null) { + mDialTintInfo.mTintBlendMode = dialTintMode; + mDialTintInfo.mHasTintBlendMode = true; + } + if (mDialTintInfo.mHasTintList || mDialTintInfo.mHasTintBlendMode) { + mDial = mDialTintInfo.apply(mDial); + } + mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour); if (mHourHand == null) { mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour); } + ColorStateList hourHandTintList = a.getColorStateList( + com.android.internal.R.styleable.AnalogClock_hand_hourTint); + if (hourHandTintList != null) { + mHourHandTintInfo.mTintList = hourHandTintList; + mHourHandTintInfo.mHasTintList = true; + } + BlendMode hourHandTintMode = Drawable.parseBlendMode( + a.getInt(com.android.internal.R.styleable.AnalogClock_hand_hourTintMode, -1), + null); + if (hourHandTintMode != null) { + mHourHandTintInfo.mTintBlendMode = hourHandTintMode; + mHourHandTintInfo.mHasTintBlendMode = true; + } + if (mHourHandTintInfo.mHasTintList || mHourHandTintInfo.mHasTintBlendMode) { + mHourHand = mHourHandTintInfo.apply(mHourHand); + } + mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute); if (mMinuteHand == null) { mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute); } + ColorStateList minuteHandTintList = a.getColorStateList( + com.android.internal.R.styleable.AnalogClock_hand_minuteTint); + if (minuteHandTintList != null) { + mMinuteHandTintInfo.mTintList = minuteHandTintList; + mMinuteHandTintInfo.mHasTintList = true; + } + BlendMode minuteHandTintMode = Drawable.parseBlendMode( + a.getInt(com.android.internal.R.styleable.AnalogClock_hand_minuteTintMode, -1), + null); + if (minuteHandTintMode != null) { + mMinuteHandTintInfo.mTintBlendMode = minuteHandTintMode; + mMinuteHandTintInfo.mHasTintBlendMode = true; + } + if (mMinuteHandTintInfo.mHasTintList || mMinuteHandTintInfo.mHasTintBlendMode) { + mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand); + } + mSecondHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_second); + ColorStateList secondHandTintList = a.getColorStateList( + com.android.internal.R.styleable.AnalogClock_hand_secondTint); + if (secondHandTintList != null) { + mSecondHandTintInfo.mTintList = secondHandTintList; + mSecondHandTintInfo.mHasTintList = true; + } + BlendMode secondHandTintMode = Drawable.parseBlendMode( + a.getInt(com.android.internal.R.styleable.AnalogClock_hand_secondTintMode, -1), + null); + if (secondHandTintMode != null) { + mSecondHandTintInfo.mTintBlendMode = secondHandTintMode; + mSecondHandTintInfo.mHasTintBlendMode = true; + } + if (mSecondHandTintInfo.mHasTintList || mSecondHandTintInfo.mHasTintBlendMode) { + mSecondHand = mSecondHandTintInfo.apply(mSecondHand); + } + mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone)); createClock(); @@ -141,6 +215,68 @@ public class AnalogClock extends View { invalidate(); } + /** + * Applies a tint to the dial drawable. + * <p> + * Subsequent calls to {@link #setDial(Icon)} will + * automatically mutate the drawable and apply the specified tint and tint + * mode using {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#AnalogClock_dialTint + * @see #getDialTintList() + * @see Drawable#setTintList(ColorStateList) + */ + @RemotableViewMethod + public void setDialTintList(@Nullable ColorStateList tint) { + mDialTintInfo.mTintList = tint; + mDialTintInfo.mHasTintList = true; + + mDial = mDialTintInfo.apply(mDial); + } + + /** + * @return the tint applied to the dial drawable + * @attr ref android.R.styleable#AnalogClock_dialTint + * @see #setDialTintList(ColorStateList) + */ + @InspectableProperty(attributeId = com.android.internal.R.styleable.AnalogClock_dialTint) + @Nullable + public ColorStateList getDialTintList() { + return mDialTintInfo.mTintList; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setDialTintList(ColorStateList)}} to the dial drawable. + * The default mode is {@link BlendMode#SRC_IN}. + * + * @param blendMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#AnalogClock_dialTintMode + * @see #getDialTintBlendMode() + * @see Drawable#setTintBlendMode(BlendMode) + */ + @RemotableViewMethod + public void setDialTintBlendMode(@Nullable BlendMode blendMode) { + mDialTintInfo.mTintBlendMode = blendMode; + mDialTintInfo.mHasTintBlendMode = true; + + mDial = mDialTintInfo.apply(mDial); + } + + /** + * @return the blending mode used to apply the tint to the dial drawable + * @attr ref android.R.styleable#AnalogClock_dialTintMode + * @see #setDialTintBlendMode(BlendMode) + */ + @InspectableProperty(attributeId = com.android.internal.R.styleable.AnalogClock_dialTintMode) + @Nullable + public BlendMode getDialTintBlendMode() { + return mDialTintInfo.mTintBlendMode; + } + /** Sets the hour hand of the clock to the specified Icon. */ @RemotableViewMethod public void setHourHand(@NonNull Icon icon) { @@ -150,6 +286,71 @@ public class AnalogClock extends View { invalidate(); } + /** + * Applies a tint to the hour hand drawable. + * <p> + * Subsequent calls to {@link #setHourHand(Icon)} will + * automatically mutate the drawable and apply the specified tint and tint + * mode using {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#AnalogClock_hand_hourTint + * @see #getHourHandTintList() + * @see Drawable#setTintList(ColorStateList) + */ + @RemotableViewMethod + public void setHourHandTintList(@Nullable ColorStateList tint) { + mHourHandTintInfo.mTintList = tint; + mHourHandTintInfo.mHasTintList = true; + + mHourHand = mHourHandTintInfo.apply(mHourHand); + } + + /** + * @return the tint applied to the hour hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_hourTint + * @see #setHourHandTintList(ColorStateList) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_hourTint + ) + @Nullable + public ColorStateList getHourHandTintList() { + return mHourHandTintInfo.mTintList; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setHourHandTintList(ColorStateList)}} to the hour hand drawable. + * The default mode is {@link BlendMode#SRC_IN}. + * + * @param blendMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#AnalogClock_hand_hourTintMode + * @see #getHourHandTintBlendMode() + * @see Drawable#setTintBlendMode(BlendMode) + */ + @RemotableViewMethod + public void setHourHandTintBlendMode(@Nullable BlendMode blendMode) { + mHourHandTintInfo.mTintBlendMode = blendMode; + mHourHandTintInfo.mHasTintBlendMode = true; + + mHourHand = mHourHandTintInfo.apply(mHourHand); + } + + /** + * @return the blending mode used to apply the tint to the hour hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_hourTintMode + * @see #setHourHandTintBlendMode(BlendMode) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_hourTintMode) + @Nullable + public BlendMode getHourHandTintBlendMode() { + return mHourHandTintInfo.mTintBlendMode; + } + /** Sets the minute hand of the clock to the specified Icon. */ @RemotableViewMethod public void setMinuteHand(@NonNull Icon icon) { @@ -160,6 +361,71 @@ public class AnalogClock extends View { } /** + * Applies a tint to the minute hand drawable. + * <p> + * Subsequent calls to {@link #setMinuteHand(Icon)} will + * automatically mutate the drawable and apply the specified tint and tint + * mode using {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#AnalogClock_hand_minuteTint + * @see #getMinuteHandTintList() + * @see Drawable#setTintList(ColorStateList) + */ + @RemotableViewMethod + public void setMinuteHandTintList(@Nullable ColorStateList tint) { + mMinuteHandTintInfo.mTintList = tint; + mMinuteHandTintInfo.mHasTintList = true; + + mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand); + } + + /** + * @return the tint applied to the minute hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_minuteTint + * @see #setMinuteHandTintList(ColorStateList) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_minuteTint + ) + @Nullable + public ColorStateList getMinuteHandTintList() { + return mMinuteHandTintInfo.mTintList; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setMinuteHandTintList(ColorStateList)}} to the minute hand drawable. + * The default mode is {@link BlendMode#SRC_IN}. + * + * @param blendMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#AnalogClock_hand_minuteTintMode + * @see #getMinuteHandTintBlendMode() + * @see Drawable#setTintBlendMode(BlendMode) + */ + @RemotableViewMethod + public void setMinuteHandTintBlendMode(@Nullable BlendMode blendMode) { + mMinuteHandTintInfo.mTintBlendMode = blendMode; + mMinuteHandTintInfo.mHasTintBlendMode = true; + + mMinuteHand = mMinuteHandTintInfo.apply(mMinuteHand); + } + + /** + * @return the blending mode used to apply the tint to the minute hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_minuteTintMode + * @see #setMinuteHandTintBlendMode(BlendMode) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_minuteTintMode) + @Nullable + public BlendMode getMinuteHandTintBlendMode() { + return mMinuteHandTintInfo.mTintBlendMode; + } + + /** * Sets the second hand of the clock to the specified Icon, or hides the second hand if it is * null. */ @@ -173,6 +439,71 @@ public class AnalogClock extends View { } /** + * Applies a tint to the second hand drawable. + * <p> + * Subsequent calls to {@link #setSecondHand(Icon)} will + * automatically mutate the drawable and apply the specified tint and tint + * mode using {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#AnalogClock_hand_secondTint + * @see #getSecondHandTintList() + * @see Drawable#setTintList(ColorStateList) + */ + @RemotableViewMethod + public void setSecondHandTintList(@Nullable ColorStateList tint) { + mSecondHandTintInfo.mTintList = tint; + mSecondHandTintInfo.mHasTintList = true; + + mSecondHand = mSecondHandTintInfo.apply(mSecondHand); + } + + /** + * @return the tint applied to the second hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_secondTint + * @see #setSecondHandTintList(ColorStateList) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_secondTint + ) + @Nullable + public ColorStateList getSecondHandTintList() { + return mSecondHandTintInfo.mTintList; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setSecondHandTintList(ColorStateList)}} to the second hand drawable. + * The default mode is {@link BlendMode#SRC_IN}. + * + * @param blendMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#AnalogClock_hand_secondTintMode + * @see #getSecondHandTintBlendMode() + * @see Drawable#setTintBlendMode(BlendMode) + */ + @RemotableViewMethod + public void setSecondHandTintBlendMode(@Nullable BlendMode blendMode) { + mSecondHandTintInfo.mTintBlendMode = blendMode; + mSecondHandTintInfo.mHasTintBlendMode = true; + + mSecondHand = mSecondHandTintInfo.apply(mSecondHand); + } + + /** + * @return the blending mode used to apply the tint to the second hand drawable + * @attr ref android.R.styleable#AnalogClock_hand_secondTintMode + * @see #setSecondHandTintBlendMode(BlendMode) + */ + @InspectableProperty( + attributeId = com.android.internal.R.styleable.AnalogClock_hand_secondTintMode) + @Nullable + public BlendMode getSecondHandTintBlendMode() { + return mSecondHandTintInfo.mTintBlendMode; + } + + /** * Indicates which time zone is currently used by this view. * * @return The ID of the current time zone or null if the default time zone, @@ -462,4 +793,36 @@ public class AnalogClock extends View { return null; } } + + private final class TintInfo { + boolean mHasTintList; + @Nullable ColorStateList mTintList; + boolean mHasTintBlendMode; + @Nullable BlendMode mTintBlendMode; + + /** + * Returns a mutated copy of {@code drawable} with tinting applied, or null if it's null. + */ + @Nullable + Drawable apply(@Nullable Drawable drawable) { + if (drawable == null) return null; + + Drawable newDrawable = drawable.mutate(); + + if (mHasTintList) { + newDrawable.setTintList(mTintList); + } + + if (mHasTintBlendMode) { + newDrawable.setTintBlendMode(mTintBlendMode); + } + + // All drawables should have the same state as the View itself. + if (drawable.isStateful()) { + newDrawable.setState(getDrawableState()); + } + + return newDrawable; + } + } } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 6dedd12a2730..23915e06335a 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -303,6 +303,27 @@ public class HorizontalScrollView extends FrameLayout { } /** + * Returns the {@link EdgeEffect#getType()} for the edge effects. + * @return the {@link EdgeEffect#getType()} for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + @EdgeEffect.EdgeEffectType + public int getEdgeEffectType() { + return mEdgeGlowLeft.getType(); + } + + /** + * Sets the {@link EdgeEffect#setType(int)} for the edge effects. + * @param type The edge effect type to use for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { + mEdgeGlowRight.setType(type); + mEdgeGlowLeft.setType(type); + invalidate(); + } + + /** * @return The maximum amount this scroll view will scroll in response to * an arrow event. */ diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 64d09de49f2d..65f3da79afe0 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -335,6 +335,27 @@ public class ScrollView extends FrameLayout { } /** + * Returns the {@link EdgeEffect#getType()} for the edge effects. + * @return the {@link EdgeEffect#getType()} for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + @EdgeEffect.EdgeEffectType + public int getEdgeEffectType() { + return mEdgeGlowTop.getType(); + } + + /** + * Sets the {@link EdgeEffect#setType(int)} for the edge effects. + * @param type The edge effect type to use for the edge effects. + * @attr ref android.R.styleable#EdgeEffect_edgeEffectType + */ + public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { + mEdgeGlowTop.setType(type); + mEdgeGlowBottom.setType(type); + invalidate(); + } + + /** * @return The maximum amount this scroll view will scroll in response to * an arrow event. */ diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java index 2904a8c889a2..0f2a3ca6936b 100644 --- a/core/java/android/widget/ToastPresenter.java +++ b/core/java/android/widget/ToastPresenter.java @@ -184,7 +184,7 @@ public class ToastPresenter { mParams.y = yOffset; mParams.horizontalMargin = horizontalMargin; mParams.verticalMargin = verticalMargin; - addToastView(); + mView.setLayoutParams(mParams); } /** diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index e82cc737a395..342456a58091 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -25,6 +25,9 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_GPU_DEADL import static android.view.SurfaceControl.JankData.PREDICTION_ERROR; import static android.view.SurfaceControl.JankData.SURFACE_FLINGER_SCHEDULING; +import static com.android.internal.jank.InteractionJankMonitor.ACTION_METRICS_LOGGED; +import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_BEGIN; + import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.HardwareRendererObserver; @@ -72,6 +75,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener private long mEndVsyncId = INVALID_ID; private boolean mMetricsFinalized; private boolean mCancelled = false; + private FrameTrackerListener mListener; private static class JankInfo { long frameVsyncId; @@ -109,7 +113,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener @NonNull SurfaceControlWrapper surfaceControlWrapper, @NonNull ChoreographerWrapper choreographer, @NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames, - int traceThresholdFrameTimeMillis) { + int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) { mSession = session; mRendererWrapper = renderer; mMetricsWrapper = metrics; @@ -120,6 +124,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler); mTraceThresholdMissedFrames = traceThresholdMissedFrames; mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis; + mListener = listener; // If the surface isn't valid yet, wait until it's created. if (viewRootWrapper.getSurfaceControl().isValid()) { @@ -165,11 +170,15 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener */ public synchronized void begin() { mBeginVsyncId = mChoreographer.getVsyncId() + 1; + mSession.setTimeStamp(System.nanoTime()); Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId); mRendererWrapper.addObserver(mObserver); if (mSurfaceControl != null) { mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl); } + if (mListener != null) { + mListener.onNotifyCujEvents(mSession, ACTION_SESSION_BEGIN); + } } /** @@ -224,7 +233,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } private boolean isInRange(long vsyncId) { - // It's possible that we may miss a callback for the frame with vsyncId == mEndVsyncId. // Because of that, we collect all frames even if they happen after the end so we eventually // have a frame after the end with both callbacks present. @@ -371,6 +379,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener missedAppFramesCount + missedSfFramesCounts, maxFrameTimeNanos, missedSfFramesCounts); + if (mListener != null) { + mListener.onNotifyCujEvents(mSession, ACTION_METRICS_LOGGED); + } } if (DEBUG) { Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName() @@ -495,4 +506,17 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener return mChoreographer.getVsyncId(); } } + + /** + * A listener that notifies cuj events. + */ + public interface FrameTrackerListener { + /** + * Notify that the CUJ session was created. + * + * @param session the CUJ session + * @param action the specific action + */ + void onNotifyCujEvents(Session session, String action); + } } diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index cba6af98a980..0294ec398484 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -16,6 +16,8 @@ package com.android.internal.jank; +import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; + import static com.android.internal.jank.FrameTracker.ChoreographerWrapper; import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; @@ -48,9 +50,12 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import android.annotation.IntDef; import android.annotation.NonNull; +import android.content.Context; +import android.content.Intent; import android.os.Build; import android.os.HandlerExecutor; import android.os.HandlerThread; +import android.os.SystemProperties; import android.provider.DeviceConfig; import android.util.Log; import android.util.SparseArray; @@ -59,6 +64,7 @@ import android.view.View; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; +import com.android.internal.jank.FrameTracker.FrameTrackerListener; import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; import com.android.internal.jank.FrameTracker.ViewRootWrapper; import com.android.internal.util.PerfettoTrigger; @@ -74,6 +80,8 @@ import java.util.concurrent.TimeUnit; */ public class InteractionJankMonitor { private static final String TAG = InteractionJankMonitor.class.getSimpleName(); + private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName(); + private static final String DEFAULT_WORKER_NAME = TAG + "-Worker"; private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L); private static final String SETTINGS_ENABLED_KEY = "enabled"; @@ -90,6 +98,14 @@ public class InteractionJankMonitor { private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3; private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64; + public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN"; + public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END"; + public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED"; + public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME"; + public static final String BUNDLE_KEY_TIMESTAMP = ACTION_PREFIX + ".TIMESTAMP"; + @VisibleForTesting + public static final String PROP_NOTIFY_CUJ_EVENT = "debug.notify_cuj_events"; + // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE. public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0; public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 1; @@ -256,15 +272,28 @@ public class InteractionJankMonitor { */ @VisibleForTesting public FrameTracker createFrameTracker(View v, Session session) { + final Context c = v.getContext().getApplicationContext(); synchronized (this) { + boolean needListener = SystemProperties.getBoolean(PROP_NOTIFY_CUJ_EVENT, false); + FrameTrackerListener eventsListener = + !needListener ? null : (s, act) -> notifyEvents(c, act, s); + return new FrameTracker(session, mWorker.getThreadHandler(), new ThreadedRendererWrapper(v.getThreadedRenderer()), new ViewRootWrapper(v.getViewRootImpl()), new SurfaceControlWrapper(), new ChoreographerWrapper(Choreographer.getInstance()), mMetrics, - mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis); + mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener); } } + private void notifyEvents(Context context, String action, Session session) { + Intent intent = new Intent(action); + intent.putExtra(BUNDLE_KEY_CUJ_NAME, getNameOfCuj(session.getCuj())); + intent.putExtra(BUNDLE_KEY_TIMESTAMP, session.getTimeStamp()); + intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY); + context.sendBroadcast(intent); + } + /** * Begin a trace session. * @@ -479,6 +508,7 @@ public class InteractionJankMonitor { public static class Session { @CujType private int mCujType; + private long mTimeStamp; public Session(@CujType int cujType) { mCujType = cujType; @@ -505,5 +535,13 @@ public class InteractionJankMonitor { public String getName() { return "J<" + getNameOfCuj(mCujType) + ">"; } + + public void setTimeStamp(long timeStamp) { + mTimeStamp = timeStamp; + } + + public long getTimeStamp() { + return mTimeStamp; + } } } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index c8afea9b0982..b99c953fa4e8 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -103,7 +103,7 @@ public final class Zygote { */ public static final int PROFILE_FROM_SHELL = 1 << 15; - /** + /* * Enable using the ART app image startup cache */ public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16; @@ -116,6 +116,13 @@ public final class Zygote { */ public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17; + /** + * Disable runtime access to {@link android.annotation.TestApi} annotated members. + * + * <p>This only takes effect if Hidden API access restrictions are enabled as well. + */ + public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18; + public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20); public static final int MEMORY_TAG_LEVEL_NONE = 0; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index cf8711b3c037..dd1a5941eed8 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -175,6 +175,7 @@ cc_library_shared { "android_hardware_Camera.cpp", "android_hardware_camera2_CameraMetadata.cpp", "android_hardware_camera2_DngCreator.cpp", + "android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp", "android_hardware_camera2_utils_SurfaceUtils.cpp", "android_hardware_display_DisplayManagerGlobal.cpp", "android_hardware_display_DisplayViewport.cpp", @@ -231,6 +232,7 @@ cc_library_shared { "audioclient-types-aidl-cpp", "audioflinger-aidl-cpp", "av-types-aidl-cpp", + "android.hardware.camera.device@3.2", "libandroidicu", "libbpf_android", "libnetdbpf", @@ -260,6 +262,7 @@ cc_library_shared { "libdataloader", "libvulkan", "libETC1", + "libjpeg", "libhardware", "libhardware_legacy", "libselinux", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 38bcc0f4c59e..1751be0af2cc 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -74,6 +74,7 @@ extern int register_android_opengl_jni_GLES32(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); +extern int register_android_hardware_camera2_impl_CameraExtensionJpegProcessor(JNIEnv* env); extern int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env); extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env); extern int register_android_hardware_HardwareBuffer(JNIEnv *env); @@ -1533,6 +1534,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), REG_JNI(register_android_hardware_camera2_DngCreator), + REG_JNI(register_android_hardware_camera2_impl_CameraExtensionJpegProcessor), REG_JNI(register_android_hardware_camera2_utils_SurfaceUtils), REG_JNI(register_android_hardware_display_DisplayManagerGlobal), REG_JNI(register_android_hardware_HardwareBuffer), diff --git a/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp new file mode 100644 index 000000000000..139075907bf3 --- /dev/null +++ b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp @@ -0,0 +1,629 @@ +/* + * 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. + */ + +#include <array> +#include <cstring> +#include <cstdio> +#include <inttypes.h> +#include <memory.h> +#include <vector> + +#include <setjmp.h> + +#include <android/hardware/camera/device/3.2/types.h> + +#include "core_jni_helpers.h" +#include "jni.h" +#include <nativehelper/JNIHelp.h> + +#define CAMERA_PROCESSOR_CLASS_NAME "android/hardware/camera2/impl/CameraExtensionJpegProcessor" + +extern "C" { +#include "jpeglib.h" +} + +using namespace std; +using namespace android; + +using android::hardware::camera::device::V3_2::CameraBlob; +using android::hardware::camera::device::V3_2::CameraBlobId; + +class Transform; +struct Plane; + +inline int sgn(int val) { return (0 < val) - (val < 0); } + +inline int min(int a, int b) { return a < b ? a : b; } + +inline int max(int a, int b) { return a > b ? a : b; } + +/** + * Represents a combined cropping and rotation transformation. + * + * The transformation maps the coordinates (mOrigX, mOrigY) and (mOneX, mOneY) + * in the input image to the origin and (mOutputWidth, mOutputHeight) + * respectively. + */ +class Transform { + public: + Transform(int origX, int origY, int oneX, int oneY); + + static Transform forCropFollowedByRotation(int cropLeft, int cropTop, + int cropRight, int cropBottom, int rot90); + + inline int getOutputWidth() const { return mOutputWidth; } + + inline int getOutputHeight() const { return mOutputHeight; } + + bool operator==(const Transform& other) const; + + /** + * Transforms the input coordinates. Coordinates outside the cropped region + * are clamped to valid values. + */ + void map(int x, int y, int* outX, int* outY) const; + + private: + int mOutputWidth; + int mOutputHeight; + + // The coordinates of the point to map the origin to. + const int mOrigX, mOrigY; + // The coordinates of the point to map the point (getOutputWidth(), + // getOutputHeight()) to. + const int mOneX, mOneY; + + // A matrix for the rotational component. + int mMat00, mMat01; + int mMat10, mMat11; +}; + +/** + * Represents a model for accessing pixel data for a single plane of an image. + * Note that the actual data is not owned by this class, and the underlying + * data does not need to be stored in separate planes. + */ +struct Plane { + // The dimensions of this plane of the image + int width; + int height; + + // A pointer to raw pixel data + const unsigned char* data; + // The difference in address between consecutive pixels in the same row + int pixelStride; + // The difference in address between the start of consecutive rows + int rowStride; +}; + +/** + * Provides an interface for simultaneously reading a certain number of rows of + * an image plane as contiguous arrays, suitable for use with libjpeg. + */ +template <unsigned int ROWS> +class RowIterator { + public: + /** + * Creates a new RowIterator which will crop and rotate with the given + * transform. + * + * @param plane the plane to iterate over + * @param transform the transformation to map output values into the + * coordinate space of the plane + * @param rowLength the length of the rows returned via LoadAt(). If this is + * longer than the width of the output (after applying the transform), then + * the right-most value is repeated. + */ + inline RowIterator(Plane plane, Transform transform, int rowLength); + + /** + * Returns an array of pointers into consecutive rows of contiguous image + * data starting at y. That is, samples within each row are contiguous. + * However, the individual arrays pointed-to may be separate. + * When the end of the image is reached, the last row of the image is + * repeated. + * The returned pointers are valid until the next call to loadAt(). + */ + inline const std::array<unsigned char*, ROWS> loadAt(int baseY); + + private: + Plane mPlane; + Transform mTransform; + // The length of a row, with padding to the next multiple of 64. + int mPaddedRowLength; + std::vector<unsigned char> mBuffer; +}; + +template <unsigned int ROWS> +RowIterator<ROWS>::RowIterator(Plane plane, Transform transform, + int rowLength) + : mPlane(plane), mTransform(transform) { + mPaddedRowLength = rowLength; + mBuffer = std::vector<unsigned char>(rowLength * ROWS); +} + +template <unsigned int ROWS> +const std::array<unsigned char*, ROWS> RowIterator<ROWS>::loadAt(int baseY) { + std::array<unsigned char*, ROWS> bufPtrs; + for (unsigned int i = 0; i < ROWS; i++) { + bufPtrs[i] = &mBuffer[mPaddedRowLength * i]; + } + + if (mPlane.width == 0 || mPlane.height == 0) { + return bufPtrs; + } + + for (unsigned int i = 0; i < ROWS; i++) { + int y = i + baseY; + y = min(y, mTransform.getOutputHeight() - 1); + + int output_width = mPaddedRowLength; + output_width = min(output_width, mTransform.getOutputWidth()); + output_width = min(output_width, mPlane.width); + + // Each row in the output image will be copied into buf_ by gathering pixels + // along an axis-aligned line in the plane. + // The line is defined by (startX, startY) -> (endX, endY), computed via the + // current Transform. + int startX; + int startY; + mTransform.map(0, y, &startX, &startY); + + int endX; + int endY; + mTransform.map(output_width - 1, y, &endX, &endY); + + // Clamp (startX, startY) and (endX, endY) to the valid bounds of the plane. + startX = min(startX, mPlane.width - 1); + startY = min(startY, mPlane.height - 1); + endX = min(endX, mPlane.width - 1); + endY = min(endY, mPlane.height - 1); + startX = max(startX, 0); + startY = max(startY, 0); + endX = max(endX, 0); + endY = max(endY, 0); + + // To reduce work inside the copy-loop, precompute the start, end, and + // stride relating the values to be gathered from mPlane into buf + // for this particular scan-line. + int dx = sgn(endX - startX); + int dy = sgn(endY - startY); + if (!(dx == 0 || dy == 0)) { + ALOGE("%s: Unexpected bounds: %dx%d %dx%d!", __FUNCTION__, startX, endX, startY, endY); + return bufPtrs; + } + + // The index into mPlane.data of (startX, startY) + int plane_start = startX * mPlane.pixelStride + startY * mPlane.rowStride; + // The index into mPlane.data of (endX, endY) + int plane_end = endX * mPlane.pixelStride + endY * mPlane.rowStride; + // The stride, in terms of indices in plane_data, required to enumerate the + // samples between the start and end points. + int stride = dx * mPlane.pixelStride + dy * mPlane.rowStride; + // In the degenerate-case of a 1x1 plane, startX and endX are equal, so + // stride would be 0, resulting in an infinite-loop. To avoid this case, + // use a stride of at-least 1. + if (stride == 0) { + stride = 1; + } + + int outX = 0; + for (int idx = plane_start; idx >= min(plane_start, plane_end) && + idx <= max(plane_start, plane_end); idx += stride) { + bufPtrs[i][outX] = mPlane.data[idx]; + outX++; + } + + // Fill the remaining right-edge of the buffer by extending the last + // value. + unsigned char right_padding_value = bufPtrs[i][outX - 1]; + for (; outX < mPaddedRowLength; outX++) { + bufPtrs[i][outX] = right_padding_value; + } + } + + return bufPtrs; +} + +template <typename T> +void safeDelete(T& t) { + delete t; + t = nullptr; +} + +template <typename T> +void safeDeleteArray(T& t) { + delete[] t; + t = nullptr; +} + +Transform::Transform(int origX, int origY, int oneX, int oneY) + : mOrigX(origX), mOrigY(origY), mOneX(oneX), mOneY(oneY) { + if (origX == oneX || origY == oneY) { + // Handle the degenerate case of cropping to a 0x0 rectangle. + mMat00 = 0; + mMat01 = 0; + mMat10 = 0; + mMat11 = 0; + return; + } + + if (oneX > origX && oneY > origY) { + // 0-degree rotation + mMat00 = 1; + mMat01 = 0; + mMat10 = 0; + mMat11 = 1; + mOutputWidth = abs(oneX - origX); + mOutputHeight = abs(oneY - origY); + } else if (oneX < origX && oneY > origY) { + // 90-degree CCW rotation + mMat00 = 0; + mMat01 = -1; + mMat10 = 1; + mMat11 = 0; + mOutputWidth = abs(oneY - origY); + mOutputHeight = abs(oneX - origX); + } else if (oneX > origX && oneY < origY) { + // 270-degree CCW rotation + mMat00 = 0; + mMat01 = 1; + mMat10 = -1; + mMat11 = 0; + mOutputWidth = abs(oneY - origY); + mOutputHeight = abs(oneX - origX);; + } else if (oneX < origX && oneY < origY) { + // 180-degree CCW rotation + mMat00 = -1; + mMat01 = 0; + mMat10 = 0; + mMat11 = -1; + mOutputWidth = abs(oneX - origX); + mOutputHeight = abs(oneY - origY); + } +} + +Transform Transform::forCropFollowedByRotation(int cropLeft, int cropTop, int cropRight, + int cropBottom, int rot90) { + // The input crop-region excludes cropRight and cropBottom, so transform the + // crop rect such that it defines the entire valid region of pixels + // inclusively. + cropRight -= 1; + cropBottom -= 1; + + int cropXLow = min(cropLeft, cropRight); + int cropYLow = min(cropTop, cropBottom); + int cropXHigh = max(cropLeft, cropRight); + int cropYHigh = max(cropTop, cropBottom); + rot90 %= 4; + if (rot90 == 0) { + return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1); + } else if (rot90 == 1) { + return Transform(cropXHigh, cropYLow, cropXLow - 1, cropYHigh + 1); + } else if (rot90 == 2) { + return Transform(cropXHigh, cropYHigh, cropXLow - 1, cropYLow - 1); + } else if (rot90 == 3) { + return Transform(cropXLow, cropYHigh, cropXHigh + 1, cropYLow - 1); + } + // Impossible case. + return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1); +} + +bool Transform::operator==(const Transform& other) const { + return other.mOrigX == mOrigX && // + other.mOrigY == mOrigY && // + other.mOneX == mOneX && // + other.mOneY == mOneY; +} + +/** + * Transforms the input coordinates. Coordinates outside the cropped region + * are clamped to valid values. + */ +void Transform::map(int x, int y, int* outX, int* outY) const { + x = max(x, 0); + y = max(y, 0); + x = min(x, getOutputWidth() - 1); + y = min(y, getOutputHeight() - 1); + *outX = x * mMat00 + y * mMat01 + mOrigX; + *outY = x * mMat10 + y * mMat11 + mOrigY; +} + +int compress(int img_width, int img_height, RowIterator<16>& y_row_generator, + RowIterator<8>& cb_row_generator, RowIterator<8>& cr_row_generator, + unsigned char* out_buf, size_t out_buf_capacity, std::function<void(size_t)> flush, + int quality) { + // libjpeg requires the use of setjmp/longjmp to recover from errors. Since + // this doesn't play well with RAII, we must use pointers and manually call + // delete. See POSIX documentation for longjmp() for details on why the + // volatile keyword is necessary. + volatile jpeg_compress_struct cinfov; + + jpeg_compress_struct& cinfo = + *const_cast<struct jpeg_compress_struct*>(&cinfov); + + JSAMPROW* volatile yArr = nullptr; + JSAMPROW* volatile cbArr = nullptr; + JSAMPROW* volatile crArr = nullptr; + + JSAMPARRAY imgArr[3]; + + // Error handling + + struct my_error_mgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; + } err; + + cinfo.err = jpeg_std_error(&err.pub); + + // Default error_exit will call exit(), so override + // to return control via setjmp/longjmp. + err.pub.error_exit = [](j_common_ptr cinfo) { + my_error_mgr* myerr = reinterpret_cast<my_error_mgr*>(cinfo->err); + + (*cinfo->err->output_message)(cinfo); + + // Return control to the setjmp point (see call to setjmp()). + longjmp(myerr->setjmp_buffer, 1); + }; + + cinfo.err = (struct jpeg_error_mgr*)&err; + + // Set the setjmp point to return to in case of error. + if (setjmp(err.setjmp_buffer)) { + // If libjpeg hits an error, control will jump to this point (see call to + // longjmp()). + jpeg_destroy_compress(&cinfo); + + safeDeleteArray(yArr); + safeDeleteArray(cbArr); + safeDeleteArray(crArr); + + return -1; + } + + // Create jpeg compression context + jpeg_create_compress(&cinfo); + + // Stores data needed by our c-style callbacks into libjpeg + struct ClientData { + unsigned char* out_buf; + size_t out_buf_capacity; + std::function<void(size_t)> flush; + int totalOutputBytes; + } clientData{out_buf, out_buf_capacity, flush, 0}; + + cinfo.client_data = &clientData; + + // Initialize destination manager + jpeg_destination_mgr dest; + + dest.init_destination = [](j_compress_ptr cinfo) { + ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data); + + cinfo->dest->next_output_byte = cdata.out_buf; + cinfo->dest->free_in_buffer = cdata.out_buf_capacity; + }; + + dest.empty_output_buffer = [](j_compress_ptr cinfo) -> boolean { + ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data); + + size_t numBytesInBuffer = cdata.out_buf_capacity; + cdata.flush(numBytesInBuffer); + cdata.totalOutputBytes += numBytesInBuffer; + + // Reset the buffer + cinfo->dest->next_output_byte = cdata.out_buf; + cinfo->dest->free_in_buffer = cdata.out_buf_capacity; + + return true; + }; + + dest.term_destination = [](j_compress_ptr cinfo __unused) { + // do nothing to terminate the output buffer + }; + + cinfo.dest = &dest; + + // Set jpeg parameters + cinfo.image_width = img_width; + cinfo.image_height = img_height; + cinfo.input_components = 3; + + // Set defaults based on the above values + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, quality, true); + + cinfo.dct_method = JDCT_IFAST; + + cinfo.raw_data_in = true; + + jpeg_set_colorspace(&cinfo, JCS_YCbCr); + + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + jpeg_start_compress(&cinfo, true); + + yArr = new JSAMPROW[cinfo.comp_info[0].v_samp_factor * DCTSIZE]; + cbArr = new JSAMPROW[cinfo.comp_info[1].v_samp_factor * DCTSIZE]; + crArr = new JSAMPROW[cinfo.comp_info[2].v_samp_factor * DCTSIZE]; + + imgArr[0] = const_cast<JSAMPARRAY>(yArr); + imgArr[1] = const_cast<JSAMPARRAY>(cbArr); + imgArr[2] = const_cast<JSAMPARRAY>(crArr); + + for (int y = 0; y < img_height; y += DCTSIZE * 2) { + std::array<unsigned char*, 16> yData = y_row_generator.loadAt(y); + std::array<unsigned char*, 8> cbData = cb_row_generator.loadAt(y / 2); + std::array<unsigned char*, 8> crData = cr_row_generator.loadAt(y / 2); + + for (int row = 0; row < DCTSIZE * 2; row++) { + yArr[row] = yData[row]; + } + for (int row = 0; row < DCTSIZE; row++) { + cbArr[row] = cbData[row]; + crArr[row] = crData[row]; + } + + jpeg_write_raw_data(&cinfo, imgArr, DCTSIZE * 2); + } + + jpeg_finish_compress(&cinfo); + + int numBytesInBuffer = cinfo.dest->next_output_byte - out_buf; + + flush(numBytesInBuffer); + + clientData.totalOutputBytes += numBytesInBuffer; + + safeDeleteArray(yArr); + safeDeleteArray(cbArr); + safeDeleteArray(crArr); + + jpeg_destroy_compress(&cinfo); + + return clientData.totalOutputBytes; +} + +int compress( + /** Input image dimensions */ + int width, int height, + /** Y Plane */ + unsigned char* yBuf, int yPStride, int yRStride, + /** Cb Plane */ + unsigned char* cbBuf, int cbPStride, int cbRStride, + /** Cr Plane */ + unsigned char* crBuf, int crPStride, int crRStride, + /** Output */ + unsigned char* outBuf, size_t outBufCapacity, + /** Jpeg compression parameters */ + int quality, + /** Crop */ + int cropLeft, int cropTop, int cropRight, int cropBottom, + /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree + * rotation. */ + int rot90) { + int finalWidth; + int finalHeight; + finalWidth = cropRight - cropLeft; + finalHeight = cropBottom - cropTop; + + rot90 %= 4; + // for 90 and 270-degree rotations, flip the final width and height + if (rot90 == 1) { + finalWidth = cropBottom - cropTop; + finalHeight = cropRight - cropLeft; + } else if (rot90 == 3) { + finalWidth = cropBottom - cropTop; + finalHeight = cropRight - cropLeft; + } + + const Plane yP = {width, height, yBuf, yPStride, yRStride}; + const Plane cbP = {width / 2, height / 2, cbBuf, cbPStride, cbRStride}; + const Plane crP = {width / 2, height / 2, crBuf, crPStride, crRStride}; + + auto flush = [](size_t numBytes __unused) { + // do nothing + }; + + // Round up to the nearest multiple of 64. + int y_row_length = (finalWidth + 16 + 63) & ~63; + int cb_row_length = (finalWidth / 2 + 16 + 63) & ~63; + int cr_row_length = (finalWidth / 2 + 16 + 63) & ~63; + + Transform yTrans = Transform::forCropFollowedByRotation( + cropLeft, cropTop, cropRight, cropBottom, rot90); + + Transform chromaTrans = Transform::forCropFollowedByRotation( + cropLeft / 2, cropTop / 2, cropRight / 2, cropBottom / 2, rot90); + + RowIterator<16> yIter(yP, yTrans, y_row_length); + RowIterator<8> cbIter(cbP, chromaTrans, cb_row_length); + RowIterator<8> crIter(crP, chromaTrans, cr_row_length); + + return compress(finalWidth, finalHeight, yIter, cbIter, crIter, outBuf, outBufCapacity, flush, + quality); +} + +extern "C" { + +static jint CameraExtensionJpegProcessor_compressJpegFromYUV420p( + JNIEnv* env, jclass clazz __unused, + /** Input image dimensions */ + jint width, jint height, + /** Y Plane */ + jobject yBuf, jint yPStride, jint yRStride, + /** Cb Plane */ + jobject cbBuf, jint cbPStride, jint cbRStride, + /** Cr Plane */ + jobject crBuf, jint crPStride, jint crRStride, + /** Output */ + jobject outBuf, jint outBufCapacity, + /** Jpeg compression parameters */ + jint quality, + /** Crop */ + jint cropLeft, jint cropTop, jint cropRight, jint cropBottom, + /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree + * rotation. */ + jint rot90) { + jbyte* y = (jbyte*)env->GetDirectBufferAddress(yBuf); + jbyte* cb = (jbyte*)env->GetDirectBufferAddress(cbBuf); + jbyte* cr = (jbyte*)env->GetDirectBufferAddress(crBuf); + jbyte* out = (jbyte*)env->GetDirectBufferAddress(outBuf); + + size_t actualJpegSize = compress(width, height, + (unsigned char*)y, yPStride, yRStride, + (unsigned char*)cb, cbPStride, cbRStride, + (unsigned char*)cr, crPStride, crRStride, + (unsigned char*)out, (size_t)outBufCapacity, + quality, cropLeft, cropTop, cropRight, cropBottom, rot90); + + size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob); + if (finalJpegSize > outBufCapacity) { + ALOGE("%s: Final jpeg buffer %zu not large enough for the jpeg blob header with "\ + "capacity %d", __FUNCTION__, finalJpegSize, outBufCapacity); + return actualJpegSize; + } + + int8_t* header = static_cast<int8_t *> (out) + + (outBufCapacity - sizeof(CameraBlob)); + CameraBlob *blob = reinterpret_cast<CameraBlob *> (header); + blob->blobId = CameraBlobId::JPEG; + blob->blobSize = actualJpegSize; + + return actualJpegSize; +} + +} // extern "C" + +static const JNINativeMethod gCameraExtensionJpegProcessorMethods[] = { + {"compressJpegFromYUV420pNative", + "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIIIIII)I", + (void*)CameraExtensionJpegProcessor_compressJpegFromYUV420p}}; + +// Get all the required offsets in java class and register native functions +int register_android_hardware_camera2_impl_CameraExtensionJpegProcessor(JNIEnv* env) { + // Register native functions + return RegisterMethodsOrDie(env, CAMERA_PROCESSOR_CLASS_NAME, + gCameraExtensionJpegProcessorMethods, NELEM(gCameraExtensionJpegProcessorMethods)); +} diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d11ee3a875aa..451ea93349f7 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -27,7 +27,6 @@ #include <android-base/chrono_utils.h> #include <android/graphics/region.h> #include <android/gui/BnScreenCaptureListener.h> -#include <android/hardware/display/IDeviceProductInfoConstants.h> #include <android/os/IInputConstants.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_hardware_HardwareBuffer.h> @@ -98,6 +97,8 @@ static struct { jfieldID supportedColorModes; jfieldID activeColorMode; jfieldID hdrCapabilities; + jfieldID autoLowLatencyModeSupported; + jfieldID gameContentTypeSupported; } gDynamicDisplayInfoClassInfo; static struct { @@ -1021,24 +1022,16 @@ static jobject convertDeviceProductInfoToJavaObject( } else { LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate"); } - jint connectionToSinkType; - // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing - // for a 5–device-deep hierarchy. For more information, refer: - // Section 8.7 - Physical Address of HDMI Specification Version 1.3a - using android::hardware::display::IDeviceProductInfoConstants; - if (info->relativeAddress.size() != 4) { - connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN; - } else if (info->relativeAddress[0] == 0) { - connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN; - } else if (info->relativeAddress[1] == 0) { - connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT; - } else { - connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE; + auto relativeAddress = env->NewIntArray(info->relativeAddress.size()); + auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr); + for (int i = 0; i < info->relativeAddress.size(); i++) { + relativeAddressData[i] = info->relativeAddress[i]; } + env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0); return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name, manufacturerPnpId, productId, modelYear, manufactureDate, - connectionToSinkType); + relativeAddress); } static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) { @@ -1134,6 +1127,11 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject to env->SetObjectField(object, gDynamicDisplayInfoClassInfo.hdrCapabilities, convertDeviceProductInfoToJavaObject(env, info.hdrCapabilities)); + env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.autoLowLatencyModeSupported, + info.autoLowLatencyModeSupported); + + env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.gameContentTypeSupported, + info.gameContentTypeSupported); return object; } @@ -1458,20 +1456,6 @@ static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj, transaction->reparent(ctrl, newParent); } -static jboolean nativeGetAutoLowLatencyModeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) { - sp<IBinder> token(ibinderForJavaObject(env, tokenObject)); - if (token == NULL) return NULL; - - return SurfaceComposerClient::getAutoLowLatencyModeSupport(token); -} - -static jboolean nativeGetGameContentTypeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) { - sp<IBinder> token(ibinderForJavaObject(env, tokenObject)); - if (token == NULL) return NULL; - - return SurfaceComposerClient::getGameContentTypeSupport(token); -} - static void nativeSetAutoLowLatencyMode(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) { sp<IBinder> token(ibinderForJavaObject(env, tokenObject)); if (token == NULL) return; @@ -1821,12 +1805,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetDisplayNativePrimaries }, {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z", (void*)nativeSetActiveColorMode}, - {"nativeGetAutoLowLatencyModeSupport", "(Landroid/os/IBinder;)Z", - (void*)nativeGetAutoLowLatencyModeSupport }, {"nativeSetAutoLowLatencyMode", "(Landroid/os/IBinder;Z)V", (void*)nativeSetAutoLowLatencyMode }, - {"nativeGetGameContentTypeSupport", "(Landroid/os/IBinder;)Z", - (void*)nativeGetGameContentTypeSupport }, {"nativeSetGameContentType", "(Landroid/os/IBinder;Z)V", (void*)nativeSetGameContentType }, {"nativeGetCompositionDataspaces", "()[I", @@ -1934,6 +1914,10 @@ int register_android_view_SurfaceControl(JNIEnv* env) gDynamicDisplayInfoClassInfo.hdrCapabilities = GetFieldIDOrDie(env, dynamicInfoClazz, "hdrCapabilities", "Landroid/view/Display$HdrCapabilities;"); + gDynamicDisplayInfoClassInfo.autoLowLatencyModeSupported = + GetFieldIDOrDie(env, dynamicInfoClazz, "autoLowLatencyModeSupported", "Z"); + gDynamicDisplayInfoClassInfo.gameContentTypeSupported = + GetFieldIDOrDie(env, dynamicInfoClazz, "gameContentTypeSupported", "Z"); jclass modeClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayMode"); gDisplayModeClassInfo.clazz = MakeGlobalRefOrDie(env, modeClazz); @@ -1986,7 +1970,7 @@ int register_android_view_SurfaceControl(JNIEnv* env) "Ljava/lang/String;" "Ljava/lang/Integer;" "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;" - "I)V"); + "[I)V"); jclass deviceProductInfoManufactureDateClazz = FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate"); diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index 62114630a328..1de1d049197c 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -17,8 +17,8 @@ <NotificationHeaderView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/notification_header" - android:layout_width="wrap_content" - android:layout_height="@dimen/notification_header_solo_height" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_header_height" android:layout_marginBottom="@dimen/notification_header_margin_bottom" android:clipChildren="false" android:gravity="center_vertical" diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml index de537b205866..2d1c3422ca36 100644 --- a/core/res/res/layout/notification_template_material_big_base.xml +++ b/core/res/res/layout/notification_template_material_big_base.xml @@ -38,11 +38,7 @@ android:layout_gravity="top" > - <include - layout="@layout/notification_template_header" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_header_big_height" - /> + <include layout="@layout/notification_template_header" /> <LinearLayout android:id="@+id/notification_main_column" diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml index 696cb6572e29..bdd4430a7985 100644 --- a/core/res/res/layout/notification_template_material_big_media.xml +++ b/core/res/res/layout/notification_template_material_big_media.xml @@ -36,7 +36,6 @@ layout="@layout/notification_template_header" android:layout_width="match_parent" android:layout_height="@dimen/media_notification_header_height" - android:layout_gravity="start" /> <LinearLayout diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml index e1b7bc4d7bca..6f3c77ff72a4 100644 --- a/core/res/res/layout/notification_template_material_big_picture.xml +++ b/core/res/res/layout/notification_template_material_big_picture.xml @@ -23,11 +23,7 @@ android:clipChildren="false" > - <include - layout="@layout/notification_template_header" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_header_big_height" - /> + <include layout="@layout/notification_template_header" /> <include layout="@layout/notification_template_right_icon" /> diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml index 2452a32b21eb..2954ba2a0903 100644 --- a/core/res/res/layout/notification_template_material_big_text.xml +++ b/core/res/res/layout/notification_template_material_big_text.xml @@ -23,11 +23,7 @@ android:tag="bigText" > - <include - layout="@layout/notification_template_header" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_header_big_height" - /> + <include layout="@layout/notification_template_header" /> <com.android.internal.widget.RemeasuringLinearLayout android:id="@+id/notification_action_list_margin_target" diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml index 7daccd2b8544..baffdd5ac0f1 100644 --- a/core/res/res/layout/notification_template_material_media.xml +++ b/core/res/res/layout/notification_template_material_media.xml @@ -32,7 +32,8 @@ /> <include layout="@layout/notification_template_header" android:layout_width="match_parent" - android:layout_height="@dimen/media_notification_header_height" /> + android:layout_height="@dimen/media_notification_header_height" + /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 99f58ee1f8a6..735e122444ef 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4127,6 +4127,94 @@ user's time zone. Please refer to {@link java.util.TimeZone} for more information about time zone ids. --> <attr name="timeZone" format="string"/> + <!-- Tint to apply to the dial graphic. --> + <attr name="dialTint" format="color" /> + <!-- Blending mode used to apply the dial graphic tint. --> + <attr name="dialTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> + <!-- Tint to apply to the hour hand graphic. --> + <attr name="hand_hourTint" format="color" /> + <!-- Blending mode used to apply the hour hand graphic tint. --> + <attr name="hand_hourTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> + <!-- Tint to apply to the minute hand graphic. --> + <attr name="hand_minuteTint" format="color" /> + <!-- Blending mode used to apply the minute hand graphic tint. --> + <attr name="hand_minuteTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> + <!-- Tint to apply to the second hand graphic. --> + <attr name="hand_secondTint" format="color" /> + <!-- Blending mode used to apply the second hand graphic tint. --> + <attr name="hand_secondTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> </declare-styleable> <declare-styleable name="Button"> </declare-styleable> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 1ca54985dfbc..695a831faf97 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -271,11 +271,8 @@ <!-- The top margin before the notification progress bar. --> <dimen name="notification_progress_margin_top">8dp</dimen> - <!-- height of the notification header when the notification is alone (minimized / groups) --> - <dimen name="notification_header_solo_height">48dp</dimen> - - <!-- height of the notification header when in a "big" layout --> - <dimen name="notification_header_big_height">56dp</dimen> + <!-- height of the notification header --> + <dimen name="notification_header_height">56dp</dimen> <!-- The height of the background for a notification header on a group --> <dimen name="notification_header_background_height">49.5dp</dimen> @@ -365,7 +362,7 @@ <dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen> <!-- The absolute height for the header in a media notification. --> - <dimen name="media_notification_header_height">@dimen/notification_header_big_height</dimen> + <dimen name="media_notification_header_height">@dimen/notification_header_height</dimen> <!-- The margin of the content to an image--> <dimen name="notification_content_image_margin_end">8dp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index a1ea61c447c0..4732e5fbf84f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3076,6 +3076,14 @@ <public name="maxResizeHeight" /> <public name="targetCellWidth" /> <public name="targetCellHeight" /> + <public name="dialTint"/> + <public name="dialTintMode"/> + <public name="hand_hourTint"/> + <public name="hand_hourTintMode"/> + <public name="hand_minuteTint"/> + <public name="hand_minuteTintMode"/> + <public name="hand_secondTint"/> + <public name="hand_secondTintMode"/> </public-group> <public-group type="drawable" first-id="0x010800b5"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e73d6e3af3cb..b5af5240b843 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4203,6 +4203,4 @@ <java-symbol type="bool" name="config_telephony5gNonStandalone" /> <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" /> - - <java-symbol type="bool" name="config_enableOneHandedKeyguard" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index e7e049da18c9..16d720b891e2 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -238,6 +238,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -271,6 +273,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -306,6 +310,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -340,6 +346,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -417,6 +425,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -449,6 +459,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -482,6 +494,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -531,6 +545,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -565,6 +581,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -597,6 +615,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -631,6 +651,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -664,6 +686,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -697,6 +721,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -730,6 +756,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -763,6 +791,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -800,6 +830,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -834,6 +866,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -865,6 +899,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -1069,6 +1105,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1101,6 +1139,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1134,6 +1174,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1169,6 +1211,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1203,6 +1247,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1281,6 +1327,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1316,6 +1364,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1352,6 +1402,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1426,6 +1478,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1463,6 +1517,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1498,6 +1554,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1532,6 +1590,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1565,6 +1625,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1598,6 +1660,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1629,6 +1693,8 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1750,6 +1816,8 @@ easier. <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorBackground">@color/background_device_default_dark</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> @@ -1782,6 +1850,8 @@ easier. <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1824,6 +1894,8 @@ easier. <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> @@ -1859,6 +1931,8 @@ easier. <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorError">@color/error_color_device_default_light</item> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS index 5031ff913e6d..80165f065995 100644 --- a/core/tests/coretests/src/android/view/OWNERS +++ b/core/tests/coretests/src/android/view/OWNERS @@ -1,7 +1,7 @@ # Input -per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com -per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com -per-file VelocityTest.java = michaelwr@google.com, svv@google.com +per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS +per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS +per-file VelocityTest.java = file:/services/core/java/com/android/server/input/OWNERS # WindowManager per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java index 10aaf317fb49..9cb7876b3e5a 100644 --- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java +++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java @@ -105,7 +105,8 @@ public class FrameTrackerTest { mTracker = Mockito.spy( new FrameTracker(session, handler, mRenderer, mViewRootWrapper, mSurfaceControlWrapper, mChoreographer, mWrapper, - /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1)); + /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1, + null)); doNothing().when(mTracker).triggerPerfetto(); } diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java index c4c475b6a0e9..8f4948c02a74 100644 --- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java +++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java @@ -96,7 +96,7 @@ public class InteractionJankMonitorTest { new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(), mock(FrameTracker.ChoreographerWrapper.class), new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1, - /*traceThresholdFrameTimeMillis=*/ -1)); + /*traceThresholdFrameTimeMillis=*/ -1, null)); doReturn(tracker).when(monitor).createFrameTracker(any(), any()); // Simulate a trace session and see if begin / end are invoked. @@ -123,21 +123,12 @@ public class InteractionJankMonitorTest { @Test public void testCheckInitState() { InteractionJankMonitor monitor = new InteractionJankMonitor(mWorker); + View view = new View(mActivity); + assertThat(view.isAttachedToWindow()).isFalse(); - // Should return false if invoking begin / end without init invocation. - assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse(); + // Should return false if the view passed in is not attached to window yet. + assertThat(monitor.begin(view, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse(); assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse(); - - // Everything should be fine if invoking init first. - boolean thrown = false; - try { - assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue(); - assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue(); - } catch (Exception ex) { - thrown = true; - } finally { - assertThat(thrown).isFalse(); - } } @Test @@ -152,7 +143,7 @@ public class InteractionJankMonitorTest { new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(), mock(FrameTracker.ChoreographerWrapper.class), new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1, - /*traceThresholdFrameTimeMillis=*/ -1)); + /*traceThresholdFrameTimeMillis=*/ -1, null)); doReturn(tracker).when(monitor).createFrameTracker(any(), any()); assertThat(monitor.begin(mView, session.getCuj())).isTrue(); diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp index 42421ce0e9f3..3536c4088dd8 100644 --- a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp @@ -50,4 +50,5 @@ apex { key: "com.android.overlaytest.overlaid.key", apps: ["OverlayRemountedTest_Target"], installable: false, + updatable: false, } diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp index 0b52dcc4fb85..f04140409bea 100644 --- a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp @@ -50,4 +50,5 @@ apex { key: "com.android.overlaytest.overlay.key", apps: ["OverlayRemountedTest_Overlay"], installable: false, + updatable: false, } diff --git a/data/etc/car/com.google.android.car.networking.preferenceupdater.xml b/data/etc/car/com.google.android.car.networking.preferenceupdater.xml index 489ce1b47ffa..cdeb8e48a59b 100644 --- a/data/etc/car/com.google.android.car.networking.preferenceupdater.xml +++ b/data/etc/car/com.google.android.car.networking.preferenceupdater.xml @@ -16,12 +16,21 @@ --> <permissions> <privapp-permissions package="com.google.android.car.networking.preferenceupdater"> - <permission name="android.permission.ACCESS_NETWORK_STATE"/> + <permission name="android.permission.ACCESS_NETWORK_STATE" /> <permission name="android.permission.ACCESS_WIFI_STATE"/> <permission name="android.permission.ACTIVITY_EMBEDDING"/> + <permission name="android.permission.CHANGE_NETWORK_STATE" /> + <permission name="android.permission.CONNECTIVITY_INTERNAL" /> + <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/> + <permission name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERNCE" /> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/> - <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/> + <permission name="android.permission.INTERNET" /> <permission name="android.permission.LOCATION_HARDWARE"/> + <permission name="android.permission.PACKAGE_USAGE_STATS" /> + <permission name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <permission name="android.permission.WAKE_LOCK" /> + <permission name="android.permission.WRITE_SETTINGS" /> + <permission name="android.car.permission.CAR_DRIVING_STATE" /> </privapp-permissions> </permissions> diff --git a/data/keyboards/OWNERS b/data/keyboards/OWNERS index c4f6df824a39..0ce83507160c 100644 --- a/data/keyboards/OWNERS +++ b/data/keyboards/OWNERS @@ -1,5 +1,3 @@ set noparent -michaelwr@google.com -svv@google.com -lzye@google.com +include /services/core/java/com/android/server/input/OWNERS diff --git a/data/keyboards/Vendor_057e_Product_2009.kl b/data/keyboards/Vendor_057e_Product_2009.kl index 3c6b11e4640c..7491ee562b59 100644 --- a/data/keyboards/Vendor_057e_Product_2009.kl +++ b/data/keyboards/Vendor_057e_Product_2009.kl @@ -74,3 +74,11 @@ key 0x135 BUTTON_MODE # Home key key 0x13c HOME + +# SENSORs +sensor 0x00 ACCELEROMETER X +sensor 0x01 ACCELEROMETER Y +sensor 0x02 ACCELEROMETER Z +sensor 0x03 GYROSCOPE X +sensor 0x04 GYROSCOPE Y +sensor 0x05 GYROSCOPE Z diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index f708298a2cbd..d00f5f669594 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -37,8 +37,6 @@ interface IKeyChainService { void setUserSelectable(String alias, boolean isUserSelectable); int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); - int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, - out KeymasterCertificateChain chain); boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain); // APIs used by CertInstaller and DevicePolicyManager diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 97819c56fd5a..f0bcfe52686d 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -44,6 +44,8 @@ import android.os.UserManager; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import android.util.Log; import com.android.org.conscrypt.TrustedCertificateStore; @@ -682,6 +684,33 @@ public final class KeyChain { return null; } + /** + * This prefix is used to disambiguate grant aliase strings from normal key alias strings. + * Technically, a key alias string can use the same prefix. However, a collision does not + * lead to privilege escalation, because grants are access controlled in the Keystore daemon. + * @hide + */ + public static final String GRANT_ALIAS_PREFIX = "ks2_keychain_grant_id:"; + + private static KeyDescriptor getGrantDescriptor(String keyid) { + KeyDescriptor result = new KeyDescriptor(); + result.domain = Domain.GRANT; + result.blob = null; + result.alias = null; + try { + result.nspace = Long.parseUnsignedLong( + keyid.substring(GRANT_ALIAS_PREFIX.length()), 16 /* radix */); + } catch (NumberFormatException e) { + return null; + } + return result; + } + + /** @hide */ + public static String getGrantString(KeyDescriptor key) { + return String.format(GRANT_ALIAS_PREFIX + "%016X", key.nspace); + } + /** @hide */ @Nullable @WorkerThread public static KeyPair getKeyPair(@NonNull Context context, @NonNull String alias) @@ -705,11 +734,23 @@ public final class KeyChain { if (keyId == null) { return null; + } + + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + try { + return android.security.keystore2.AndroidKeyStoreProvider + .loadAndroidKeyStoreKeyPairFromKeystore( + KeyStore2.getInstance(), + getGrantDescriptor(keyId)); + } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { + throw new KeyChainException(e); + } } else { try { return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore( KeyStore.getInstance(), keyId, KeyStore.UID_SELF); - } catch (RuntimeException | UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { + } catch (RuntimeException | UnrecoverableKeyException + | KeyPermanentlyInvalidatedException e) { throw new KeyChainException(e); } } @@ -827,11 +868,8 @@ public final class KeyChain { @Deprecated public static boolean isBoundKeyAlgorithm( @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { - if (!isKeyAlgorithmSupported(algorithm)) { - return false; - } - - return KeyStore.getInstance().isHardwareBacked(algorithm); + // All supported algorithms are hardware backed. Individual keys may not be. + return true; } /** @hide */ diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java index c20cf01a993e..a6e33664f2b1 100644 --- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java @@ -59,7 +59,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(mSpec.getKeystoreAlias()); out.writeInt(mSpec.getPurposes()); - out.writeInt(mSpec.getUid()); + out.writeInt(mSpec.getNamespace()); out.writeInt(mSpec.getKeySize()); // Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec. @@ -125,7 +125,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { private ParcelableKeyGenParameterSpec(Parcel in) { final String keystoreAlias = in.readString(); final int purposes = in.readInt(); - final int uid = in.readInt(); + final int namespace = in.readInt(); final int keySize = in.readInt(); final int keySpecType = in.readInt(); @@ -177,7 +177,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { // KeyGenParameterSpec constructor (whereas using a builder would silently drop them). mSpec = new KeyGenParameterSpec( keystoreAlias, - uid, + namespace, keySize, algorithmSpec, certificateSubject, diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index b3bfd6a3a97a..e401add9ece7 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -154,7 +154,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private KeyGenParameterSpec mSpec; private String mEntryAlias; - private int mEntryUid; + private int mEntryNamespace; private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm; private int mKeymasterAlgorithm = -1; private int mKeySizeBits; @@ -218,7 +218,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } mEntryAlias = spec.getKeystoreAlias(); - mEntryUid = spec.getUid(); + mEntryNamespace = spec.getNamespace(); mSpec = spec; mKeymasterAlgorithm = keymasterAlgorithm; mKeySizeBits = spec.getKeySize(); @@ -439,7 +439,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private void resetAll() { mEntryAlias = null; - mEntryUid = KeyProperties.NAMESPACE_APPLICATION; + mEntryNamespace = KeyProperties.NAMESPACE_APPLICATION; mJcaKeyAlgorithm = null; mKeymasterAlgorithm = -1; mKeymasterPurposes = null; @@ -541,10 +541,10 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato KeyDescriptor descriptor = new KeyDescriptor(); descriptor.alias = mEntryAlias; - descriptor.domain = mEntryUid == KeyProperties.NAMESPACE_APPLICATION + descriptor.domain = mEntryNamespace == KeyProperties.NAMESPACE_APPLICATION ? Domain.APP : Domain.SELINUX; - descriptor.nspace = mEntryUid; + descriptor.nspace = mEntryNamespace; descriptor.blob = null; boolean success = false; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index e1011155248e..35059ac929c3 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -273,10 +273,10 @@ public class AndroidKeyStoreProvider extends Provider { /** @hide **/ @NonNull public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore( - @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace) + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { AndroidKeyStoreKey key = - loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace); + loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); if (key instanceof AndroidKeyStorePublicKey) { AndroidKeyStorePublicKey publicKey = (AndroidKeyStorePublicKey) key; return new KeyPair(publicKey, publicKey.getPrivateKey()); @@ -336,7 +336,7 @@ public class AndroidKeyStoreProvider extends Provider { @NonNull public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace) - throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { KeyDescriptor descriptor = new KeyDescriptor(); if (namespace == KeyProperties.NAMESPACE_APPLICATION) { @@ -348,6 +348,18 @@ public class AndroidKeyStoreProvider extends Provider { } descriptor.alias = alias; descriptor.blob = null; + + final AndroidKeyStoreKey key = loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); + if (key instanceof AndroidKeyStorePublicKey) { + return ((AndroidKeyStorePublicKey) key).getPrivateKey(); + } else { + return key; + } + } + + private static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { KeyEntryResponse response = null; try { response = keyStore.getKeyEntry(descriptor); @@ -397,7 +409,7 @@ public class AndroidKeyStoreProvider extends Provider { keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata, new KeyStoreSecurityLevel(response.iSecurityLevel), - keymasterAlgorithm).getPrivateKey(); + keymasterAlgorithm); } else { throw new UnrecoverableKeyException("Key algorithm unknown"); } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index 3282ece999ac..10aea519f18b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -18,239 +18,92 @@ package com.android.wm.shell.flicker import android.graphics.Region import android.view.Surface -import com.android.server.wm.flicker.dsl.LayersAssertionBuilder -import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.traces.layers.getVisibleBounds -@JvmOverloads -fun LayersAssertionBuilder.appPairsDividerIsVisible(bugId: Int = 0) { - end("appPairsDividerIsVisible", bugId) { +fun FlickerTestParameter.appPairsDividerIsVisible() { + assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.appPairsDividerIsInvisible(bugId: Int = 0) { - end("appPairsDividerIsInVisible", bugId) { +fun FlickerTestParameter.appPairsDividerIsInvisible() { + assertLayersEnd { this.notExists(APP_PAIR_SPLIT_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.appPairsDividerBecomesVisible(bugId: Int = 0) { - all("dividerLayerBecomesVisible", bugId) { +fun FlickerTestParameter.appPairsDividerBecomesVisible() { + assertLayers { this.hidesLayer(DOCKED_STACK_DIVIDER) .then() .showsLayer(DOCKED_STACK_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.dockedStackDividerIsVisible(bugId: Int = 0) { - end("dockedStackDividerIsVisible", bugId) { +fun FlickerTestParameter.dockedStackDividerIsVisible() { + assertLayersEnd { this.isVisible(DOCKED_STACK_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.dockedStackDividerBecomesVisible(bugId: Int = 0) { - all("dividerLayerBecomesVisible", bugId) { +fun FlickerTestParameter.dockedStackDividerBecomesVisible() { + assertLayers { this.hidesLayer(DOCKED_STACK_DIVIDER) .then() .showsLayer(DOCKED_STACK_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.dockedStackDividerBecomesInvisible(bugId: Int = 0) { - all("dividerLayerBecomesInvisible", bugId) { +fun FlickerTestParameter.dockedStackDividerBecomesInvisible() { + assertLayers { this.showsLayer(DOCKED_STACK_DIVIDER) .then() .hidesLayer(DOCKED_STACK_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.dockedStackDividerIsInvisible(bugId: Int = 0) { - end("dockedStackDividerIsInvisible", bugId) { +fun FlickerTestParameter.dockedStackDividerIsInvisible() { + assertLayersEnd { this.notExists(DOCKED_STACK_DIVIDER) } } -@JvmOverloads -fun LayersAssertionBuilder.appPairsPrimaryBoundsIsVisible( - rotation: Int, - primaryLayerName: String, - bugId: Int = 0 -) { - end("PrimaryAppBounds", bugId) { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation)) - } -} - -@JvmOverloads -fun LayersAssertionBuilder.appPairsSecondaryBoundsIsVisible( - rotation: Int, - secondaryLayerName: String, - bugId: Int = 0 -) { - end("SecondaryAppBounds", bugId) { +fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) { + assertLayersEnd { val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation)) - } -} - -@JvmOverloads -fun LayersAssertionBuilder.dockedStackPrimaryBoundsIsVisible( - rotation: Int, - primaryLayerName: String, - bugId: Int = 0 -) { - end("PrimaryAppBounds", bugId) { - val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation)) } } -@JvmOverloads -fun LayersAssertionBuilder.dockedStackSecondaryBoundsIsVisible( +fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisible( rotation: Int, - secondaryLayerName: String, - bugId: Int = 0 + primaryLayerName: String ) { - end("SecondaryAppBounds", bugId) { + assertLayersEnd { val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) - this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation)) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.appPairsDividerIsVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("appPairsDividerIsVisible", bugId, enabled) { - this.isVisible(APP_PAIR_SPLIT_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.appPairsDividerIsInvisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("appPairsDividerIsInVisible", bugId, enabled) { - this.notExists(APP_PAIR_SPLIT_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.appPairsDividerBecomesVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("dividerLayerBecomesVisible", bugId, enabled) { - this.hidesLayer(DOCKED_STACK_DIVIDER) - .then() - .showsLayer(DOCKED_STACK_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackDividerIsVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("dockedStackDividerIsVisible", bugId, enabled) { - this.isVisible(DOCKED_STACK_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("dividerLayerBecomesVisible", bugId, enabled) { - this.hidesLayer(DOCKED_STACK_DIVIDER) - .then() - .showsLayer(DOCKED_STACK_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesInvisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("dividerLayerBecomesInvisible", bugId, enabled) { - this.showsLayer(DOCKED_STACK_DIVIDER) - .then() - .hidesLayer(DOCKED_STACK_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackDividerIsInvisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("dockedStackDividerIsInvisible", bugId, enabled) { - this.notExists(DOCKED_STACK_DIVIDER) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.appPairsPrimaryBoundsIsVisible( - rotation: Int, - primaryLayerName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("PrimaryAppBounds", bugId, enabled) { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation)) } } -@JvmOverloads -fun LayersAssertionBuilderLegacy.appPairsSecondaryBoundsIsVisible( +fun FlickerTestParameter.appPairsSecondaryBoundsIsVisible( rotation: Int, - secondaryLayerName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 + secondaryLayerName: String ) { - end("SecondaryAppBounds", bugId, enabled) { + assertLayersEnd { val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation)) } } -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackPrimaryBoundsIsVisible( +fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisible( rotation: Int, - primaryLayerName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 + secondaryLayerName: String ) { - end("PrimaryAppBounds", bugId, enabled) { - val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) - this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation)) - } -} - -@JvmOverloads -fun LayersAssertionBuilderLegacy.dockedStackSecondaryBoundsIsVisible( - rotation: Int, - secondaryLayerName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - end("SecondaryAppBounds", bugId, enabled) { + assertLayersEnd { val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER) this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation)) } @@ -260,10 +113,10 @@ fun getPrimaryRegion(dividerRegion: Region, rotation: Int): Region { val displayBounds = WindowUtils.getDisplayBounds(rotation) return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { Region(0, 0, displayBounds.bounds.right, - dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset) + dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset) } else { Region(0, 0, dividerRegion.bounds.left, - dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset) + dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset) } } @@ -271,12 +124,12 @@ fun getSecondaryRegion(dividerRegion: Region, rotation: Int): Region { val displayBounds = WindowUtils.getDisplayBounds(rotation) return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { Region(0, - dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.bounds.right, - displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset) + dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset, + displayBounds.bounds.right, + displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset) } else { Region(dividerRegion.bounds.right, 0, - displayBounds.bounds.right, - displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset) + displayBounds.bounds.right, + displayBounds.bounds.bottom - WindowUtils.dockedStackDividerInset) } -} +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt index 89bbdb0a2f99..9c50630095be 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt @@ -16,33 +16,33 @@ package com.android.wm.shell.flicker +import android.app.Instrumentation import android.content.pm.PackageManager import android.content.pm.PackageManager.FEATURE_LEANBACK import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY -import android.os.RemoteException -import android.os.SystemClock -import android.platform.helpers.IAppHelper import android.view.Surface import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice -import com.android.server.wm.flicker.Flicker import org.junit.Assume.assumeFalse import org.junit.Before +import org.junit.runners.Parameterized /** * Base class of all Flicker test that performs common functions for all flicker tests: * - * * - Caches transitions so that a transition is run once and the transition results are used by * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods * multiple times. * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed. * - Fails tests if results are not available for any test due to jank. */ -abstract class FlickerTestBase { - val instrumentation by lazy { InstrumentationRegistry.getInstrumentation() } - val uiDevice by lazy { UiDevice.getInstance(instrumentation) } - val packageManager: PackageManager by lazy { instrumentation.context.getPackageManager() } +abstract class FlickerTestBase( + protected val rotationName: String, + protected val rotation: Int +) { + val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + val uiDevice = UiDevice.getInstance(instrumentation) + val packageManager: PackageManager = instrumentation.context.packageManager protected val isTelevision: Boolean by lazy { packageManager.run { hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY) @@ -56,83 +56,12 @@ abstract class FlickerTestBase { @Before open fun televisionSetUp() = assumeFalse(isTelevision) - /** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param rotation Initial screen rotation - * - * @return test tag with pattern <NAME>__<APP>__<ROTATION> - </ROTATION></APP></NAME> */ - protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String { - return buildTestTag( - testName, app, rotation, rotation, app2 = null, extraInfo = "") - } - - /** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param beginRotation Initial screen rotation - * @param endRotation End screen rotation (if any, otherwise use same as initial) - * - * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION> - </END_ROTATION></BEGIN_ROTATION></APP></NAME> */ - protected fun buildTestTag( - testName: String, - app: IAppHelper, - beginRotation: Int, - endRotation: Int - ): String { - return buildTestTag( - testName, app, beginRotation, endRotation, app2 = null, extraInfo = "") - } - - /** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param app2 Second app being launched (if any) - * @param beginRotation Initial screen rotation - * @param endRotation End screen rotation (if any, otherwise use same as initial) - * @param extraInfo Additional information to append to the tag - * - * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>] - </EXTRA></NAME> */ - protected fun buildTestTag( - testName: String, - app: IAppHelper, - beginRotation: Int, - endRotation: Int, - app2: IAppHelper?, - extraInfo: String - ): String { - var testTag = "${testName}__${app.launcherName}" - if (app2 != null) { - testTag += "-${app2.launcherName}" - } - testTag += "__${Surface.rotationToString(beginRotation)}" - if (endRotation != beginRotation) { - testTag += "-${Surface.rotationToString(endRotation)}" - } - if (extraInfo.isNotEmpty()) { - testTag += "__$extraInfo" - } - return testTag - } - - protected fun Flicker.setRotation(rotation: Int) { - try { - when (rotation) { - Surface.ROTATION_270 -> device.setOrientationLeft() - Surface.ROTATION_90 -> device.setOrientationRight() - Surface.ROTATION_0 -> device.setOrientationNatural() - else -> device.setOrientationNatural() - } - // Wait for animation to complete - SystemClock.sleep(1000) - } catch (e: RemoteException) { - throw RuntimeException(e) + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90) + return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt deleted file mode 100644 index 90334ae91e9d..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker - -import android.view.Surface -import org.junit.runners.Parameterized - -abstract class NonRotationTestBase( - protected val rotationName: String, - protected val rotation: Int -) : FlickerTestBase() { - companion object { - const val SCREENSHOT_LAYER = "RotationLayer" - - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90) - return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt index c3fd66395366..5d51b2fd515f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt @@ -18,15 +18,16 @@ package com.android.wm.shell.flicker.apppairs import android.os.Bundle import android.os.SystemClock +import android.platform.test.annotations.Presubmit import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.appPairsDividerIsInvisible +import com.android.wm.shell.flicker.helpers.AppPairsHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -41,47 +42,47 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class AppPairsTestCannotPairNonResizeableApps( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag(configuration) - } - transitions { - nonResizeableApp?.launchViaIntent(wmHelper) - // TODO pair apps through normal UX flow - executeShellCommand( - composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - } - assertions { - presubmit { - layersTrace { - appPairsDividerIsInvisible() - } - windowManagerTrace { - val nonResizeableApp = nonResizeableApp - require(nonResizeableApp != null) { - "Non resizeable app not initialized" - } + testSpec: FlickerTestParameter +) : AppPairsTransition(testSpec) { - end("onlyResizeableAppWindowVisible") { - isVisible(nonResizeableApp.defaultWindowName) - isInvisible(primaryApp.defaultWindowName) - } - } - } - } + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + super.transition(this, it) + transitions { + nonResizeableApp?.launchViaIntent(wmHelper) + // TODO pair apps through normal UX flow + executeShellCommand( + composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) } + } + + @Presubmit + @Test + fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible() - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - transition, testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS) + @Presubmit + @Test + fun onlyResizeableAppWindowVisible() { + val nonResizeableApp = nonResizeableApp + require(nonResizeableApp != null) { + "Non resizeable app not initialized" + } + testSpec.assertWmEnd { + isVisible(nonResizeableApp.defaultWindowName) + isInvisible(primaryApp.defaultWindowName) + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + repetitions = AppPairsHelper.TEST_REPETITIONS) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt index 7a2a5e482d98..77890ba8ed15 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt @@ -18,17 +18,19 @@ package com.android.wm.shell.flicker.apppairs import android.os.Bundle import android.os.SystemClock +import android.platform.test.annotations.Presubmit +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.traces.layers.getVisibleBounds import com.android.wm.shell.flicker.appPairsDividerIsVisible import com.android.wm.shell.flicker.helpers.AppPairsHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -39,52 +41,53 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class AppPairsTestPairPrimaryAndSecondaryApps( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : AppPairsTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + super.transition(this, it) + transitions { + // TODO pair apps through normal UX flow + executeShellCommand( + composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + } + } + + @Presubmit + @Test + fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + + @Presubmit + @Test + fun bothAppWindowsVisible() { + testSpec.assertWmEnd { + isVisible(primaryApp.defaultWindowName) + isVisible(secondaryApp.defaultWindowName) + } + } + + @FlakyTest + @Test + fun appsEndingBounds() { + testSpec.assertLayersEnd { + val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) + this.hasVisibleRegion(primaryApp.defaultWindowName, + appPairsHelper.getPrimaryBounds(dividerRegion)) + .hasVisibleRegion(secondaryApp.defaultWindowName, + appPairsHelper.getSecondaryBounds(dividerRegion)) + } + } + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag(configuration) - } - transitions { - // TODO pair apps through normal UX flow - executeShellCommand( - composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - } - assertions { - presubmit { - layersTrace { - appPairsDividerIsVisible() - } - windowManagerTrace { - end("bothAppWindowsVisible") { - isVisible(primaryApp.defaultWindowName) - isVisible(secondaryApp.defaultWindowName) - } - } - } - - flaky { - layersTrace { - end("appsEndingBounds") { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - this.hasVisibleRegion(primaryApp.defaultWindowName, - appPairsHelper.getPrimaryBounds(dividerRegion)) - .hasVisibleRegion(secondaryApp.defaultWindowName, - appPairsHelper.getSecondaryBounds(dividerRegion)) - } - } - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, transition, - testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS) + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + repetitions = AppPairsHelper.TEST_REPETITIONS) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt index d8dc4c2b56f6..3d3ca0cfd450 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt @@ -18,17 +18,19 @@ package com.android.wm.shell.flicker.apppairs import android.os.Bundle import android.os.SystemClock +import android.platform.test.annotations.Presubmit +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.traces.layers.getVisibleBounds import com.android.wm.shell.flicker.appPairsDividerIsInvisible import com.android.wm.shell.flicker.helpers.AppPairsHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -39,61 +41,67 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class AppPairsTestUnpairPrimaryAndSecondaryApps( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : AppPairsTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + super.transition(this, it) + setup { + executeShellCommand( + composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + } + transitions { + // TODO pair apps through normal UX flow + executeShellCommand( + composePairsCommand(primaryTaskId, secondaryTaskId, pair = false)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + } + } + + @Presubmit + @Test + fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible() + + @Presubmit + @Test + fun bothAppWindowsInvisible() { + testSpec.assertWmEnd { + isInvisible(primaryApp.defaultWindowName) + isInvisible(secondaryApp.defaultWindowName) + } + } + + @FlakyTest + @Test + fun appsStartingBounds() { + testSpec.assertLayersStart { + val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) + hasVisibleRegion(primaryApp.defaultWindowName, + appPairsHelper.getPrimaryBounds(dividerRegion)) + hasVisibleRegion(secondaryApp.defaultWindowName, + appPairsHelper.getSecondaryBounds(dividerRegion)) + } + } + + @FlakyTest + @Test + fun appsEndingBounds() { + testSpec.assertLayersEnd { + notExists(primaryApp.defaultWindowName) + notExists(secondaryApp.defaultWindowName) + } + } + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag(configuration) - } - setup { - executeShellCommand( - composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - } - transitions { - // TODO pair apps through normal UX flow - executeShellCommand( - composePairsCommand(primaryTaskId, secondaryTaskId, pair = false)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - } - assertions { - presubmit { - layersTrace { - appPairsDividerIsInvisible() - } - windowManagerTrace { - end("bothAppWindowsInvisible") { - isInvisible(primaryApp.defaultWindowName) - isInvisible(secondaryApp.defaultWindowName) - } - } - } - - flaky { - layersTrace { - start("appsStartingBounds") { - val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER) - this.hasVisibleRegion(primaryApp.defaultWindowName, - appPairsHelper.getPrimaryBounds(dividerRegion)) - .hasVisibleRegion(secondaryApp.defaultWindowName, - appPairsHelper.getSecondaryBounds(dividerRegion)) - } - end("appsEndingBounds") { - this.notExists(primaryApp.defaultWindowName) - .notExists(secondaryApp.defaultWindowName) - } - } - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, transition, - testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS) + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + repetitions = AppPairsHelper.TEST_REPETITIONS) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt index 78a938aef69e..9e6752db224f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt @@ -18,38 +18,53 @@ package com.android.wm.shell.flicker.apppairs import android.app.Instrumentation import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.system.helpers.ActivityHelper import android.util.Log +import androidx.test.platform.app.InstrumentationRegistry import com.android.compatibility.common.util.SystemUtil +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.SplitScreenHelper import com.android.wm.shell.flicker.testapp.Components +import org.junit.Test import java.io.IOException -open class AppPairsTransition( - protected val instrumentation: Instrumentation -) { - internal val activityHelper = ActivityHelper.getInstance() - - internal val appPairsHelper = AppPairsHelper(instrumentation, +abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected val isRotated = testSpec.config.startRotation.isRotated() + protected val activityHelper = ActivityHelper.getInstance() + protected val appPairsHelper = AppPairsHelper(instrumentation, Components.SplitScreenActivity.LABEL, Components.SplitScreenActivity.COMPONENT) - internal val primaryApp = SplitScreenHelper.getPrimary(instrumentation) - internal val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) - internal open val nonResizeableApp: SplitScreenHelper? = + protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation) + protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) + protected open val nonResizeableApp: SplitScreenHelper? = SplitScreenHelper.getNonResizeable(instrumentation) - internal var primaryTaskId = "" - internal var secondaryTaskId = "" - internal var nonResizeableTaskId = "" + protected var primaryTaskId = "" + protected var secondaryTaskId = "" + protected var nonResizeableTaskId = "" + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + transition(this, testSpec.config) + } + } internal open val transition: FlickerBuilder.(Bundle) -> Unit get() = { configuration -> @@ -71,20 +86,9 @@ open class AppPairsTransition( primaryTaskId, secondaryTaskId, pair = false)) executeShellCommand(composePairsCommand( primaryTaskId, nonResizeableTaskId, pair = false)) - primaryApp.exit() - secondaryApp.exit() - nonResizeableApp?.exit() - } - } - - assertions { - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - } - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() + primaryApp.exit(wmHelper) + secondaryApp.exit(wmHelper) + nonResizeableApp?.exit(wmHelper) } } } @@ -128,4 +132,20 @@ open class AppPairsTransition( } append("$primaryApp $secondaryApp") } + + @Presubmit + @Test + open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt index 8aee005b7513..35a0020b16a9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt @@ -18,25 +18,25 @@ package com.android.wm.shell.flicker.apppairs import android.os.Bundle import android.os.SystemClock +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.appPairsDividerIsVisible import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -47,57 +47,65 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateTwoLaunchedAppsInAppPairsMode( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : RotateTwoLaunchedAppsTransition( - InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag(configuration) - } - transitions { - executeShellCommand(composePairsCommand( - primaryTaskId, secondaryTaskId, true /* pair */)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - setRotation(configuration.endRotation) - } - assertions { - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - end("bothAppWindowsVisible") { - isVisible(primaryApp.defaultWindowName) - .isVisible(secondaryApp.defaultWindowName) - } - } - } - - flaky { - layersTrace { - appPairsDividerIsVisible() - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - appPairsPrimaryBoundsIsVisible(configuration.endRotation, - primaryApp.defaultWindowName, bugId = 172776659) - appPairsSecondaryBoundsIsVisible(configuration.endRotation, - secondaryApp.defaultWindowName, bugId = 172776659) - } - } - } + testSpec: FlickerTestParameter +) : RotateTwoLaunchedAppsTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + super.transition(this, it) + transitions { + executeShellCommand(composePairsCommand( + primaryTaskId, secondaryTaskId, true /* pair */)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + setRotation(testSpec.config.endRotation) } + } + + @Presubmit + @Test + fun bothAppWindowsVisible() { + testSpec.assertWmEnd { + isVisible(primaryApp.defaultWindowName) + .isVisible(secondaryApp.defaultWindowName) + } + } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - transition, testSpec, + @FlakyTest + @Test + fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, + testSpec.config.endRotation) + + @FlakyTest + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, + testSpec.config.endRotation) + + @FlakyTest(bugId = 172776659) + @Test + fun appPairsPrimaryBoundsIsVisible() = + testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation, + primaryApp.defaultWindowName) + + @FlakyTest(bugId = 172776659) + @Test + fun appPairsSecondaryBoundsIsVisible() = + testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation, + secondaryApp.defaultWindowName) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270)) + supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270) + ) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt index bc99c9430f13..326a775acc8d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt @@ -20,18 +20,16 @@ import android.os.Bundle import android.os.SystemClock import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.appPairsDividerIsVisible @@ -39,7 +37,9 @@ import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -48,70 +48,84 @@ import org.junit.runners.Parameterized * Test open apps to app pairs and rotate. * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsRotateAndEnterAppPairsMode` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : RotateTwoLaunchedAppsTransition( - InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag(configuration) - } - transitions { - this.setRotation(configuration.endRotation) - executeShellCommand( - composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) - SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) - } - assertions { - val isRotated = configuration.startRotation.isRotated() - presubmit { - layersTrace { - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - appPairsDividerIsVisible() - if (!isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - end("bothAppWindowsVisible") { - isVisible(primaryApp.defaultWindowName) - isVisible(secondaryApp.defaultWindowName) - } - } - } - flaky { - layersTrace { - appPairsPrimaryBoundsIsVisible(configuration.endRotation, - primaryApp.defaultWindowName, 172776659) - appPairsSecondaryBoundsIsVisible(configuration.endRotation, - secondaryApp.defaultWindowName, 172776659) - - if (isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - } - } + testSpec: FlickerTestParameter +) : RotateTwoLaunchedAppsTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + super.transition(this, it) + transitions { + this.setRotation(testSpec.config.endRotation) + executeShellCommand( + composePairsCommand(primaryTaskId, secondaryTaskId, pair = true)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) } + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, + testSpec.config.endRotation) + + @Presubmit + @Test + fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible() + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(isRotated) + testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(isRotated) + testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation) + } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - transition, testSpec, + @Presubmit + @Test + override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun bothAppWindowsVisible() { + testSpec.assertWmEnd { + isVisible(primaryApp.defaultWindowName) + isVisible(secondaryApp.defaultWindowName) + } + } + + @FlakyTest(bugId = 172776659) + @Test + fun appPairsPrimaryBoundsIsVisible() = + testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation, + primaryApp.defaultWindowName) + + @FlakyTest(bugId = 172776659) + @Test + fun appPairsSecondaryBoundsIsVisible() = + testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation, + secondaryApp.defaultWindowName) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270) ) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt index 8ea2544fcf61..271b25fc0ce1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt @@ -16,17 +16,17 @@ package com.android.wm.shell.flicker.apppairs -import android.app.Instrumentation import android.os.Bundle import android.view.Surface +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.wm.shell.flicker.helpers.SplitScreenHelper -open class RotateTwoLaunchedAppsTransition( - instrumentation: Instrumentation -) : AppPairsTransition(instrumentation) { +abstract class RotateTwoLaunchedAppsTransition( + testSpec: FlickerTestParameter +) : AppPairsTransition(testSpec) { override val nonResizeableApp: SplitScreenHelper? get() = null @@ -45,8 +45,8 @@ open class RotateTwoLaunchedAppsTransition( eachRun { executeShellCommand(composePairsCommand( primaryTaskId, secondaryTaskId, pair = false)) - primaryApp.exit() - secondaryApp.exit() + primaryApp.exit(wmHelper) + secondaryApp.exit(wmHelper) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt index 0d9edd29d259..9b70fac737e6 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.WALLPAPER_TITLE import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.startRotation @@ -36,6 +36,7 @@ import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -47,56 +48,74 @@ import org.junit.runners.Parameterized @Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) // @FlakyTest(bugId = 179116910) class EnterSplitScreenDockActivity( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + device.launchSplitScreen(wmHelper) + } + } + + @FlakyTest(bugId = 169271943) + @Test + fun dockedStackPrimaryBoundsIsVisible() = + testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, + splitScreenApp.defaultWindowName) + + @Presubmit + @Test + fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible() + + @FlakyTest(bugId = 178531736) + @Test + // b/178531736 + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, + WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME, + splitScreenApp.defaultWindowName) + ) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @FlakyTest(bugId = 178531736) + @Test + // b/178531736 + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, + WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME, + splitScreenApp.defaultWindowName) + ) + + @Presubmit + @Test + fun appWindowIsVisible() { + testSpec.assertWmEnd { + isVisible(splitScreenApp.defaultWindowName) + } + } + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testLegacySplitScreenDockActivity", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - device.launchSplitScreen(wmHelper) - } - assertions { - layersTrace { - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, bugId = 169271943) - dockedStackDividerBecomesVisible() - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, - WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME, - splitScreenApp.defaultWindowName), - bugId = 178531736 - ) - } - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, - WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME, - splitScreenApp.defaultWindowName), - bugId = 178531736 - ) - end("appWindowIsVisible") { - isVisible(splitScreenApp.defaultWindowName) - } - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, defaultTransitionSetup, testSpec, + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 ) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt index a513ee1e91f1..bd57a59ea3d9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible @@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -46,61 +47,79 @@ import org.junit.runners.Parameterized * Test open activity to primary split screen and dock secondary activity to side * To run this test: `atest WMShellFlickerTests:EnterSplitScreenLaunchToSide` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class EnterSplitScreenLaunchToSide( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + device.launchSplitScreen(wmHelper) + device.reopenAppFromOverview(wmHelper) + } + } + + @FlakyTest(bugId = 169271943) + @Test + fun dockedStackPrimaryBoundsIsVisible() = + testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, + splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 169271943) + @Test + fun dockedStackSecondaryBoundsIsVisible() = + testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, + secondaryApp.defaultWindowName) + + @Presubmit + @Test + // b/169271943 + fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible() + + @FlakyTest(bugId = 178447631) + @Test + // TODO(b/178447631) Remove Splash Screen from white list when flicker lib + // add a wait for splash screen be gone + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME, + splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + @Presubmit + @Test + fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME, + splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testLegacySplitScreenLaunchToSide", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - } - assertions { - layersTrace { - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, bugId = 169271943) - dockedStackSecondaryBoundsIsVisible( - configuration.startRotation, - secondaryApp.defaultWindowName, bugId = 169271943) - dockedStackDividerBecomesVisible() - // TODO(b/178447631) Remove Splash Screen from white list when flicker lib - // add a wait for splash screen be gone - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME, - splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - appWindowBecomesVisible(secondaryApp.defaultWindowName) - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, SPLASH_SCREEN_NAME, - splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName) - ) - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, defaultTransitionSetup, testSpec, + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842 ) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt index 78ed773f2409..67578b29a36c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt @@ -17,16 +17,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle -import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.WALLPAPER_TITLE import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.canSplitScreen import com.android.server.wm.flicker.helpers.openQuickstep import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry @@ -35,6 +33,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsInvisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.Assert import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -43,64 +42,68 @@ import org.junit.runners.Parameterized * Test open non-resizable activity will auto exit split screen mode * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNonResizableNotDock` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FlakyTest(bugId = 173875043) class EnterSplitScreenNonResizableNotDock( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testLegacySplitScreenNonResizeableActivityNotDock", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - teardown { - eachRun { - nonResizeableApp.exit(wmHelper) - } - } - transitions { - nonResizeableApp.launchViaIntent(wmHelper) - device.openQuickstep(wmHelper) - if (device.canSplitScreen(wmHelper)) { - Assert.fail("Non-resizeable app should not enter split screen") - } + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + teardown { + eachRun { + nonResizeableApp.exit(wmHelper) } - assertions { - layersTrace { - dockedStackDividerIsInvisible() - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, - SPLASH_SCREEN_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(WALLPAPER_TITLE, - LAUNCHER_PACKAGE_NAME, - SPLASH_SCREEN_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName) - ) - end("appWindowIsVisible") { - isInvisible(nonResizeableApp.defaultWindowName) - } - } + } + transitions { + nonResizeableApp.launchViaIntent(wmHelper) + device.openQuickstep(wmHelper) + if (device.canSplitScreen(wmHelper)) { + Assert.fail("Non-resizeable app should not enter split screen") } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, cleanSetup, testSpec, + } + + @Test + fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible() + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, + SPLASH_SCREEN_NAME, + nonResizeableApp.defaultWindowName, + splitScreenApp.defaultWindowName) + ) + + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(WALLPAPER_TITLE, + LAUNCHER_PACKAGE_NAME, + SPLASH_SCREEN_NAME, + nonResizeableApp.defaultWindowName, + splitScreenApp.defaultWindowName) + ) + + @Test + fun appWindowIsVisible() { + testSpec.assertWmEnd { + isInvisible(nonResizeableApp.defaultWindowName) + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt index f4e5ba7877da..5d42a4a8fae0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.layerBecomesInvisible @@ -36,6 +36,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -44,61 +45,72 @@ import org.junit.runners.Parameterized * Test open resizeable activity split in primary, and drag divider to bottom exit split screen * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottom` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class ExitLegacySplitScreenFromBottom( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testExitLegacySplitScreenFromBottom", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - teardown { - eachRun { - splitScreenApp.exit(wmHelper) - } - } - transitions { - device.exitSplitScreenFromBottom() + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + setup { + eachRun { + splitScreenApp.launchViaIntent(wmHelper) + device.launchSplitScreen(wmHelper) } - assertions { - layersTrace { - layerBecomesInvisible(DOCKED_STACK_DIVIDER) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - appWindowBecomesInVisible(secondaryApp.defaultWindowName) - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName), - bugId = 178447631 - ) - } + } + teardown { + eachRun { + splitScreenApp.exit(wmHelper) } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, defaultTransitionSetup, testSpec, + transitions { + device.exitSplitScreenFromBottom() + } + } + + @Presubmit + @Test + fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(DOCKED_STACK_DIVIDER) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + @Presubmit + @Test + fun appWindowBecomesInVisible() = + testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @FlakyTest(bugId = 178447631) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842 + supportedRotations = listOf(Surface.ROTATION_0) // b/175687842 ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt index 8737fc5f8430..ff8f9c6ed865 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt @@ -17,14 +17,15 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.layerBecomesInvisible @@ -35,6 +36,7 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn import com.android.wm.shell.flicker.dockedStackDividerIsInvisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -46,56 +48,71 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class ExitPrimarySplitScreenShowSecondaryFullscreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testExitPrimarySplitScreenShowSecondaryFullscreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - teardown { - eachRun { - secondaryApp.exit(wmHelper) - } - } - transitions { - splitScreenApp.launchViaIntent(wmHelper) - secondaryApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - // TODO(b/175687842) Can not find Split screen divider, use exit() instead - splitScreenApp.exit(wmHelper) - } - assertions { - layersTrace { - dockedStackDividerIsInvisible(bugId = 175687842) - layerBecomesInvisible(splitScreenApp.defaultWindowName) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - appWindowBecomesInVisible(splitScreenApp.defaultWindowName) - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, - secondaryApp.defaultWindowName), - bugId = 178447631 - ) - } + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + teardown { + eachRun { + secondaryApp.exit(wmHelper) } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, defaultTransitionSetup, testSpec, + transitions { + splitScreenApp.launchViaIntent(wmHelper) + secondaryApp.launchViaIntent(wmHelper) + device.launchSplitScreen(wmHelper) + device.reopenAppFromOverview(wmHelper) + // TODO(b/175687842) Can not find Split screen divider, use exit() instead + splitScreenApp.exit(wmHelper) + } + } + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible() + + @Presubmit + @Test + fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + @Presubmit + @Test + fun appWindowBecomesInVisible() = + testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @FlakyTest(bugId = 178447631) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName, + secondaryApp.defaultWindowName) + ) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 ) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt new file mode 100644 index 000000000000..893b101d0759 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt @@ -0,0 +1,48 @@ +/* + * 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.flicker.legacysplitscreen + +import android.os.Bundle +import android.view.Surface +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen + +abstract class LegacySplitScreenRotateTransition( + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + setup { + eachRun { + device.wakeUpAndGoToHomeScreen() + device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) + secondaryApp.launchViaIntent(wmHelper) + splitScreenApp.launchViaIntent(wmHelper) + } + } + teardown { + eachRun { + splitScreenApp.exit(wmHelper) + secondaryApp.exit(wmHelper) + this.setRotation(Surface.ROTATION_0) + } + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt index c0feaee73d9a..09a7e31d20e2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt @@ -16,18 +16,19 @@ package com.android.wm.shell.flicker.legacysplitscreen +import android.os.Bundle import android.platform.test.annotations.Presubmit import android.support.test.launcherhelper.LauncherStrategyFactory import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.focusDoesNotChange -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.exitSplitScreen -import com.android.server.wm.flicker.helpers.isInSplitScreen import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview import com.android.server.wm.flicker.helpers.setRotation @@ -39,13 +40,13 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt import com.android.server.wm.flicker.layerBecomesInvisible import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible import com.android.wm.shell.flicker.helpers.SimpleAppHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -54,80 +55,100 @@ import org.junit.runners.Parameterized * Test open app to split screen. * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncher` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class LegacySplitScreenToLauncher( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation) - .launcherStrategy.supportedLauncherPackage - val testApp = SimpleAppHelper(instrumentation) + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + private val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation) + .launcherStrategy.supportedLauncherPackage + private val testApp = SimpleAppHelper(instrumentation) - // b/161435597 causes the test not to work on 90 degrees - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0)) { configuration -> - withTestName { - buildTestTag("splitScreenToLauncher", configuration) + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + setup { + test { + device.wakeUpAndGoToHomeScreen() + device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.endRotation) - device.launchSplitScreen(wmHelper) - } + eachRun { + testApp.launchViaIntent(wmHelper) + this.setRotation(configuration.endRotation) + device.launchSplitScreen(wmHelper) + device.waitForIdle() } - teardown { - eachRun { - testApp.exit() - } - test { - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - } - } - transitions { - device.exitSplitScreen() - } - assertions { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.endRotation) - navBarLayerRotatesAndScales(configuration.endRotation) - statusBarLayerRotatesScales(configuration.endRotation) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(launcherPackageName)) - - // b/161435597 causes the test not to work on 90 degrees - dockedStackDividerBecomesInvisible() - - layerBecomesInvisible(testApp.getPackage()) - } - - eventLog { - focusDoesNotChange(bugId = 151179149) - } + } + teardown { + eachRun { + testApp.exit(wmHelper) } } + transitions { + device.exitSplitScreen() + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation) + + @Presubmit + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation) + + @Presubmit + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(launcherPackageName)) + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible() + + @Presubmit + @Test + fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(testApp.getPackage()) + + @FlakyTest(bugId = 151179149) + @Test + fun focusDoesNotChange() = testSpec.focusDoesNotChange() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + // b/161435597 causes the test not to work on 90 degrees + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt index f9d2f49186a7..6ab1f0bfdb89 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt @@ -20,31 +20,28 @@ import android.app.Instrumentation import android.os.Bundle import android.support.test.launcherhelper.LauncherStrategyFactory import android.view.Surface +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.exitSplitScreen -import com.android.server.wm.flicker.helpers.isInSplitScreen +import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview -import com.android.server.wm.flicker.helpers.openQuickstep import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.wm.shell.flicker.helpers.SplitScreenHelper -abstract class LegacySplitScreenTransition( - protected val instrumentation: Instrumentation -) { - internal val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation) - internal val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) - internal val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation) - internal val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation) +abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected val isRotated = testSpec.config.startRotation.isRotated() + protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation) + protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) + protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation) + protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation) .launcherStrategy.supportedLauncherPackage - internal val LIVE_WALLPAPER_PACKAGE_NAME = - "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2" - internal val LETTERBOX_NAME = "Letterbox" - internal val TOAST_NAME = "Toast" - internal val SPLASH_SCREEN_NAME = "Splash Screen" - internal open val defaultTransitionSetup: FlickerBuilder.(Bundle) -> Unit + protected open val transition: FlickerBuilder.(Bundle) -> Unit get() = { configuration -> setup { eachRun { @@ -57,17 +54,22 @@ abstract class LegacySplitScreenTransition( } teardown { eachRun { - // TODO(b/175687842) Workaround for exit legacy split screen - device.openQuickstep(wmHelper) - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - device.pressHome() + secondaryApp.exit(wmHelper) + splitScreenApp.exit(wmHelper) this.setRotation(Surface.ROTATION_0) } } } + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + transition(this, testSpec.config) + } + } + internal open val cleanSetup: FlickerBuilder.(Bundle) -> Unit get() = { configuration -> setup { @@ -79,37 +81,19 @@ abstract class LegacySplitScreenTransition( } teardown { eachRun { - // TODO(b/175687842) Workaround for exit legacy split screen - device.openQuickstep(wmHelper) - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } + nonResizeableApp.exit(wmHelper) + splitScreenApp.exit(wmHelper) device.pressHome() this.setRotation(Surface.ROTATION_0) } } } - internal open val customRotateSetup: FlickerBuilder.(Bundle) -> Unit - get() = { configuration -> - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - secondaryApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - } - } - teardown { - eachRun { - // TODO(b/175687842) Workaround for exit legacy split screen - device.openQuickstep(wmHelper) - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - device.pressHome() - this.setRotation(Surface.ROTATION_0) - } - } - } + companion object { + internal const val LIVE_WALLPAPER_PACKAGE_NAME = + "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2" + internal const val LETTERBOX_NAME = "Letterbox" + internal const val TOAST_NAME = "Toast" + internal const val SPLASH_SCREEN_NAME = "Splash Screen" + } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt index a8de8db719a8..1b4b54a74eab 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt @@ -19,15 +19,15 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.layerBecomesInvisible @@ -36,6 +36,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -45,61 +46,73 @@ import org.junit.runners.Parameterized * (Non resizable activity launch via recent overview) * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class NonResizableDismissInLegacySplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testNonResizableDismissInLegacySplitScreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - setup { - eachRun { - nonResizeableApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - device.reopenAppFromOverview(wmHelper) - } - assertions { - layersTrace { - layerBecomesVisible(nonResizeableApp.defaultWindowName) - layerBecomesInvisible(splitScreenApp.defaultWindowName) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, - LETTERBOX_NAME, TOAST_NAME, - splitScreenApp.defaultWindowName, - nonResizeableApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - appWindowBecomesVisible(nonResizeableApp.defaultWindowName) - appWindowBecomesInVisible(splitScreenApp.defaultWindowName) - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, - LETTERBOX_NAME, TOAST_NAME, - splitScreenApp.defaultWindowName, - nonResizeableApp.defaultWindowName), - bugId = 178447631 - ) - } + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + cleanSetup(this, configuration) + setup { + eachRun { + nonResizeableApp.launchViaIntent(wmHelper) + splitScreenApp.launchViaIntent(wmHelper) + device.launchSplitScreen(wmHelper) } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, cleanSetup, testSpec, + transitions { + device.reopenAppFromOverview(wmHelper) + } + } + + @Presubmit + @Test + fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, + LETTERBOX_NAME, TOAST_NAME, + splitScreenApp.defaultWindowName, + nonResizeableApp.defaultWindowName) + ) + + @Presubmit + @Test + fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + + @Presubmit + @Test + fun appWindowBecomesVisible() = + testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + + @Presubmit + @Test + fun appWindowBecomesInVisible() = + testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, + LETTERBOX_NAME, TOAST_NAME, + splitScreenApp.defaultWindowName, + nonResizeableApp.defaultWindowName) + ) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt index c82c80237912..2365e3bfd8c3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt @@ -19,15 +19,15 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesInVisible import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.layerBecomesInvisible import com.android.server.wm.flicker.layerBecomesVisible @@ -35,6 +35,7 @@ import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEnt import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -47,60 +48,73 @@ import org.junit.runners.Parameterized @Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class NonResizableLaunchInLegacySplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testNonResizableLaunchInLegacySplitScreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - nonResizeableApp.launchViaIntent(wmHelper) - wmHelper.waitForAppTransitionIdle() - } - assertions { - layersTrace { - layerBecomesVisible(nonResizeableApp.defaultWindowName) - layerBecomesInvisible(splitScreenApp.defaultWindowName) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(DOCKED_STACK_DIVIDER, - LAUNCHER_PACKAGE_NAME, - LETTERBOX_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName), - bugId = 178447631 - ) - } - windowManagerTrace { - appWindowBecomesVisible(nonResizeableApp.defaultWindowName) - appWindowBecomesInVisible(splitScreenApp.defaultWindowName) - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(DOCKED_STACK_DIVIDER, - LAUNCHER_PACKAGE_NAME, - LETTERBOX_NAME, - nonResizeableApp.defaultWindowName, - splitScreenApp.defaultWindowName), - bugId = 178447631 - ) - } + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + cleanSetup(this, configuration) + setup { + eachRun { + splitScreenApp.launchViaIntent(wmHelper) + device.launchSplitScreen(wmHelper) } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, cleanSetup, testSpec, + transitions { + nonResizeableApp.launchViaIntent(wmHelper) + wmHelper.waitForAppTransitionIdle() + } + } + + @Presubmit + @Test + fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + + @Presubmit + @Test + fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(DOCKED_STACK_DIVIDER, + LAUNCHER_PACKAGE_NAME, + LETTERBOX_NAME, + nonResizeableApp.defaultWindowName, + splitScreenApp.defaultWindowName) + ) + + @Presubmit + @Test + fun appWindowBecomesVisible() = + testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + + @Presubmit + @Test + fun appWindowBecomesInVisible() = + testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(DOCKED_STACK_DIVIDER, + LAUNCHER_PACKAGE_NAME, + LETTERBOX_NAME, + nonResizeableApp.defaultWindowName, + splitScreenApp.defaultWindowName) + ) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt index 9199c39535ac..b369a3d32e64 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.layerBecomesVisible import com.android.server.wm.flicker.noUncoveredRegions @@ -34,10 +34,10 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.appPairsDividerBecomesVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -46,54 +46,66 @@ import org.junit.runners.Parameterized * Test open app to split screen. * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreen` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class OpenAppToLegacySplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val wmHelper = WindowManagerStateHelper() - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testOpenAppToLegacySplitScreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - device.launchSplitScreen(wmHelper) - wmHelper.waitForAppTransitionIdle() - } - assertions { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName), - bugId = 178447631) - appWindowBecomesVisible(splitScreenApp.getPackage()) - } + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + device.launchSplitScreen(wmHelper) + wmHelper.waitForAppTransitionIdle() + } + } - layersTrace { - noUncoveredRegions(configuration.startRotation, enabled = false) - statusBarLayerIsAlwaysVisible() - appPairsDividerBecomesVisible() - layerBecomesVisible(splitScreenApp.getPackage()) - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName), - bugId = 178447631) - } + @FlakyTest(bugId = 178447631) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName) + ) - eventLog { - focusChanges(splitScreenApp.`package`, - "recents_animation_input_consumer", "NexusLauncherActivity", - bugId = 151179149) - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, defaultTransitionSetup, testSpec, + @Presubmit + @Test + fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage()) + + @FlakyTest + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible() + + @Presubmit + @Test + fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage()) + + @FlakyTest(bugId = 178447631) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry( + listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName) + ) + + @FlakyTest(bugId = 151179149) + @Test + fun focusChanges() = testSpec.focusChanges(splitScreenApp.`package`, + "recents_animation_input_consumer", "NexusLauncherActivity") + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 ) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt index c305bd856f58..ffffa1902976 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt @@ -16,24 +16,21 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Presubmit import android.graphics.Region +import android.os.Bundle import android.util.Rational import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.flicker.focusDoesNotChange import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.exitSplitScreen -import com.android.server.wm.flicker.helpers.isInSplitScreen import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.resizeSplitScreen import com.android.server.wm.flicker.helpers.setRotation @@ -42,7 +39,6 @@ import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales @@ -52,6 +48,7 @@ import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.traces.layers.getVisibleBounds import com.android.wm.shell.flicker.helpers.SimpleAppHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -62,14 +59,162 @@ import org.junit.runners.Parameterized * * Currently it runs only in 0 degrees because of b/156100803 */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 159096424) class ResizeLegacySplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { + testSpec: FlickerTestParameter +) : LegacySplitScreenTransition(testSpec) { + private val testAppTop = SimpleAppHelper(instrumentation) + private val testAppBottom = ImeAppHelper(instrumentation) + + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + setup { + eachRun { + device.wakeUpAndGoToHomeScreen() + this.setRotation(configuration.startRotation) + this.launcherStrategy.clearRecentAppsFromOverview() + testAppBottom.launchViaIntent(wmHelper) + device.pressHome() + testAppTop.launchViaIntent(wmHelper) + device.waitForIdle() + device.launchSplitScreen(wmHelper) + val snapshot = + device.findObject(By.res(device.launcherPackageName, "snapshot")) + snapshot.click() + testAppBottom.openIME(device) + device.pressBack() + device.resizeSplitScreen(startRatio) + } + } + teardown { + eachRun { + testAppTop.exit(wmHelper) + testAppBottom.exit(wmHelper) + } + } + transitions { + device.resizeSplitScreen(stopRatio) + } + } + + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 156223549) + @Test + fun topAppWindowIsAlwaysVisible() { + testSpec.assertWm { + this.showsAppWindow(sSimpleActivity) + } + } + + @FlakyTest(bugId = 156223549) + @Test + fun bottomAppWindowIsAlwaysVisible() { + testSpec.assertWm { + this.showsAppWindow(sImeActivity) + } + } + + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation) + + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.endRotation) + + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation) + + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Test + fun topAppLayerIsAlwaysVisible() { + testSpec.assertLayers { + this.showsLayer(sSimpleActivity) + } + } + + @Test + fun bottomAppLayerIsAlwaysVisible() { + testSpec.assertLayers { + this.showsLayer(sImeActivity) + } + } + + @Test + fun dividerLayerIsAlwaysVisible() { + testSpec.assertLayers { + this.showsLayer(DOCKED_STACK_DIVIDER) + } + } + + @FlakyTest + @Test + fun appsStartingBounds() { + testSpec.assertLayersStart { + val displayBounds = WindowUtils.displayBounds + val dividerBounds = + entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds + + val topAppBounds = Region(0, 0, dividerBounds.right, + dividerBounds.top + WindowUtils.dockedStackDividerInset) + val bottomAppBounds = Region(0, + dividerBounds.bottom - WindowUtils.dockedStackDividerInset, + displayBounds.right, + displayBounds.bottom - WindowUtils.navigationBarHeight) + this.hasVisibleRegion("SimpleActivity", topAppBounds) + .hasVisibleRegion("ImeActivity", bottomAppBounds) + } + } + + @FlakyTest + @Test + fun appsEndingBounds() { + testSpec.assertLayersStart { + val displayBounds = WindowUtils.displayBounds + val dividerBounds = + entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds + + val topAppBounds = Region(0, 0, dividerBounds.right, + dividerBounds.top + WindowUtils.dockedStackDividerInset) + val bottomAppBounds = Region(0, + dividerBounds.bottom - WindowUtils.dockedStackDividerInset, + displayBounds.right, + displayBounds.bottom - WindowUtils.navigationBarHeight) + + this.hasVisibleRegion(sSimpleActivity, topAppBounds) + .hasVisibleRegion(sImeActivity, bottomAppBounds) + } + } + + @Test + fun focusDoesNotChange() { + testSpec.assertEventLog { + focusDoesNotChange() + } + } + companion object { private const val sSimpleActivity = "SimpleActivity" private const val sImeActivity = "ImeActivity" @@ -78,126 +223,14 @@ class ResizeLegacySplitScreen( @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testAppTop = SimpleAppHelper(instrumentation) - val testAppBottom = ImeAppHelper(instrumentation) - - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0)) { configuration -> - withTestName { - val description = (startRatio.toString().replace("/", "-") + "_to_" + - stopRatio.toString().replace("/", "-")) - buildTestTag("resizeSplitScreen", configuration, description) - } - repeat { configuration.repetitions } - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - this.setRotation(configuration.startRotation) - this.launcherStrategy.clearRecentAppsFromOverview() - testAppBottom.launchViaIntent(wmHelper) - device.pressHome() - testAppTop.launchViaIntent(wmHelper) - device.waitForIdle() - device.launchSplitScreen(wmHelper) - val snapshot = - device.findObject(By.res(device.launcherPackageName, "snapshot")) - snapshot.click() - testAppBottom.openIME(device) - device.pressBack() - device.resizeSplitScreen(startRatio) - } - } - teardown { - eachRun { - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - device.pressHome() - testAppTop.exit() - testAppBottom.exit() - } - test { - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - } - } - transitions { - device.resizeSplitScreen(stopRatio) - } - assertions { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - - all("topAppWindowIsAlwaysVisible", bugId = 156223549) { - this.showsAppWindow(sSimpleActivity) - } - - all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) { - this.showsAppWindow(sImeActivity) - } - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.endRotation) - navBarLayerRotatesAndScales(configuration.endRotation) - statusBarLayerRotatesScales(configuration.endRotation) - visibleLayersShownMoreThanOneConsecutiveEntry() - - all("topAppLayerIsAlwaysVisible") { - this.showsLayer(sSimpleActivity) - } - - all("bottomAppLayerIsAlwaysVisible") { - this.showsLayer(sImeActivity) - } - - all("dividerLayerIsAlwaysVisible") { - this.showsLayer(DOCKED_STACK_DIVIDER) - } - - start("appsStartingBounds", enabled = false) { - val displayBounds = WindowUtils.displayBounds - val dividerBounds = - entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds - - val topAppBounds = Region(0, 0, dividerBounds.right, - dividerBounds.top + WindowUtils.dockedStackDividerInset) - val bottomAppBounds = Region(0, - dividerBounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.right, - displayBounds.bottom - WindowUtils.navigationBarHeight) - this.hasVisibleRegion("SimpleActivity", topAppBounds) - .hasVisibleRegion("ImeActivity", bottomAppBounds) - } - - end("appsEndingBounds", enabled = false) { - val displayBounds = WindowUtils.displayBounds - val dividerBounds = - entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds - - val topAppBounds = Region(0, 0, dividerBounds.right, - dividerBounds.top + WindowUtils.dockedStackDividerInset) - val bottomAppBounds = Region(0, - dividerBounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.right, - displayBounds.bottom - WindowUtils.navigationBarHeight) - - this.hasVisibleRegion(sSimpleActivity, topAppBounds) - .hasVisibleRegion(sImeActivity, bottomAppBounds) - } - } - - eventLog { - focusDoesNotChange() - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) + .map { + val description = (startRatio.toString().replace("/", "-") + "_to_" + + stopRatio.toString().replace("/", "-")) + val newName = "${FlickerTestParameter.defaultName(it.config)}_$description" + FlickerTestParameter(it.config, name = newName) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt index 40bdaf3df5e8..c538008aa179 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales @@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsVisible import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -46,50 +47,64 @@ import org.junit.runners.Parameterized * Test dock activity to primary split screen and rotate * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppAndEnterSplitScreen` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateOneLaunchedAppAndEnterSplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : LegacySplitScreenRotateTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + device.launchSplitScreen(wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackPrimaryBoundsIsVisible() = + testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, + splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 169271943) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @FlakyTest(bugId = 169271943) + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun appWindowBecomesVisible() = + testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName) + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testRotateOneLaunchedAppAndEnterSplitScreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - device.launchSplitScreen(wmHelper) - this.setRotation(configuration.startRotation) - } - assertions { - layersTrace { - dockedStackDividerIsVisible(bugId = 175687842) - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, bugId = 175687842) - navBarLayerRotatesAndScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - statusBarLayerRotatesScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - } - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - appWindowBecomesVisible(splitScreenApp.defaultWindowName) - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, customRotateSetup, testSpec, - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = SplitScreenHelper.TEST_REPETITIONS, + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt index ae2c2d8f1bf2..c1162560119c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerRotatesAndScales @@ -38,6 +38,7 @@ import com.android.wm.shell.flicker.dockedStackDividerIsVisible import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -46,50 +47,61 @@ import org.junit.runners.Parameterized * Rotate * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppInSplitScreenMode` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateOneLaunchedAppInSplitScreenMode( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : LegacySplitScreenRotateTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + this.setRotation(testSpec.config.startRotation) + device.launchSplitScreen(wmHelper) + } + } + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackPrimaryBoundsIsVisible() = testSpec.dockedStackPrimaryBoundsIsVisible( + testSpec.config.startRotation, splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 169271943) + @Test + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @FlakyTest(bugId = 169271943) + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun appWindowBecomesVisible() = + testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName) + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testRotateOneLaunchedAppInSplitScreenMode", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - this.setRotation(configuration.startRotation) - device.launchSplitScreen(wmHelper) - } - assertions { - layersTrace { - dockedStackDividerIsVisible(bugId = 175687842) - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, bugId = 175687842) - navBarLayerRotatesAndScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - statusBarLayerRotatesScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - } - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - appWindowBecomesVisible(splitScreenApp.defaultWindowName) - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, customRotateSetup, testSpec, + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt index aa9ac8f9782f..273925c0361c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.helpers.setRotation @@ -40,6 +40,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -48,54 +49,69 @@ import org.junit.runners.Parameterized * Test open app to split screen. * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppAndEnterSplitScreen` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateTwoLaunchedAppAndEnterSplitScreen( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { + testSpec: FlickerTestParameter +) : LegacySplitScreenRotateTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + transitions { + this.setRotation(testSpec.config.startRotation) + device.launchSplitScreen(wmHelper) + device.reopenAppFromOverview(wmHelper) + } + } + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackPrimaryBoundsIsVisible() = + testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, + splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackSecondaryBoundsIsVisible() = + testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, + secondaryApp.defaultWindowName) + + @FlakyTest(bugId = 169271943) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @FlakyTest(bugId = 169271943) + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @Presubmit + @Test + fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testRotateTwoLaunchedAppAndEnterSplitScreen", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - transitions { - this.setRotation(configuration.startRotation) - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - } - assertions { - layersTrace { - dockedStackDividerIsVisible(bugId = 175687842) - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, 175687842) - dockedStackSecondaryBoundsIsVisible( - configuration.startRotation, - secondaryApp.defaultWindowName, bugId = 175687842) - navBarLayerRotatesAndScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - statusBarLayerRotatesScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - } - windowManagerTrace { - appWindowBecomesVisible(secondaryApp.defaultWindowName) - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - } - } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, customRotateSetup, testSpec, + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt index 0e864dbbb75d..c7188dc227e7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.os.Bundle import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.appWindowBecomesVisible import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.helpers.setRotation @@ -40,6 +40,7 @@ import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -48,59 +49,76 @@ import org.junit.runners.Parameterized * Test open app to split screen. * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppInSplitScreenMode` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class RotateTwoLaunchedAppInSplitScreenMode( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : LegacySplitScreenTransition(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - buildTestTag("testRotateTwoLaunchedAppInSplitScreenMode", configuration) - } - repeat { SplitScreenHelper.TEST_REPETITIONS } - setup { - eachRun { - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - this.setRotation(configuration.startRotation) - } - } - transitions { - this.setRotation(configuration.startRotation) - } - assertions { - layersTrace { - dockedStackDividerIsVisible(bugId = 175687842) - dockedStackPrimaryBoundsIsVisible( - configuration.startRotation, - splitScreenApp.defaultWindowName, bugId = 175687842) - dockedStackSecondaryBoundsIsVisible( - configuration.startRotation, - secondaryApp.defaultWindowName, bugId = 175687842) - navBarLayerRotatesAndScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - statusBarLayerRotatesScales( - configuration.startRotation, - configuration.endRotation, bugId = 169271943) - } - windowManagerTrace { - appWindowBecomesVisible(secondaryApp.defaultWindowName) - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } + testSpec: FlickerTestParameter +) : LegacySplitScreenRotateTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + super.transition(this, configuration) + setup { + eachRun { + device.launchSplitScreen(wmHelper) + device.reopenAppFromOverview(wmHelper) + this.setRotation(testSpec.config.startRotation) } } - return FlickerTestRunnerFactory.getInstance().buildTest( - instrumentation, customRotateSetup, testSpec, + transitions { + this.setRotation(testSpec.config.startRotation) + } + } + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackPrimaryBoundsIsVisible() = + testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation, + splitScreenApp.defaultWindowName) + + @FlakyTest(bugId = 175687842) + @Test + fun dockedStackSecondaryBoundsIsVisible() = + testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation, + secondaryApp.defaultWindowName) + + @FlakyTest(bugId = 169271943) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @FlakyTest(bugId = 169271943) + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @Presubmit + @Test + fun appWindowBecomesVisible() = + testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName) + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0 /* bugId = 178685668 */)) + supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt deleted file mode 100644 index bc42d5ed04ce..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.pip - -import android.os.SystemClock -import com.android.wm.shell.flicker.NonRotationTestBase - -abstract class AppTestBase( - rotationName: String, - rotation: Int -) : NonRotationTestBase(rotationName, rotation) { - companion object { - fun waitForAnimationComplete() { - // TODO: UiDevice doesn't have reliable way to wait for the completion of animation. - // Consider to introduce WindowManagerStateHelper to access Activity state. - SystemClock.sleep(1000) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt index d56ed02972fb..ca48eaa45840 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt @@ -16,11 +16,14 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.wm.shell.flicker.helpers.FixedAppHelper import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible @@ -29,6 +32,7 @@ import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -39,64 +43,96 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class EnterExitPipTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<Array<Any>> { - val testApp = FixedAppHelper(instrumentation) - val testSpec = getTransition(eachRun = true) { configuration -> - setup { - eachRun { - testApp.launchViaIntent(wmHelper) - } - } - transitions { - // This will bring PipApp to fullscreen - pipApp.launchViaIntent(wmHelper) - } - assertions { - val displayBounds = WindowUtils.getDisplayBounds(configuration.startRotation) - presubmit { - windowManagerTrace { - all("pipApp must remain inside visible bounds") { - coversAtMostRegion(pipApp.defaultWindowName, displayBounds) - } - all("Initially shows both app windows then pipApp hides testApp") { - showsAppWindow(testApp.defaultWindowName) - .showsAppWindowOnTop(pipApp.defaultWindowName) - .then() - .hidesAppWindow(testApp.defaultWindowName) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - all("Initially shows both app layers then pipApp hides testApp") { - showsLayer(testApp.defaultWindowName) - .showsLayer(pipApp.defaultWindowName) - .then() - .hidesLayer(testApp.defaultWindowName) - } - start("testApp covers the fullscreen, pipApp remains inside display") { - hasVisibleRegion(testApp.defaultWindowName, displayBounds) - coversAtMostRegion(displayBounds, pipApp.defaultWindowName) - } - end("pipApp covers the fullscreen") { - hasVisibleRegion(pipApp.defaultWindowName, displayBounds) - } - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - } - } + testSpec: FlickerTestParameter +) : PipTransition(testSpec) { + private val testApp = FixedAppHelper(instrumentation) + private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = true) { + setup { + eachRun { + testApp.launchViaIntent(wmHelper) } } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) + transitions { + // This will bring PipApp to fullscreen + pipApp.launchViaIntent(wmHelper) + } + } + + @Presubmit + @Test + fun pipAppRemainInsideVisibleBounds() { + testSpec.assertWm { + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + } + + @Presubmit + @Test + fun showBothAppWindowsThenHidePip() { + testSpec.assertWm { + showsAppWindow(testApp.defaultWindowName) + .showsAppWindowOnTop(pipApp.defaultWindowName) + .then() + .hidesAppWindow(testApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun showBothAppLayersThenHidePip() { + testSpec.assertLayers { + showsLayer(testApp.defaultWindowName) + .showsLayer(pipApp.defaultWindowName) + .then() + .hidesLayer(testApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun testAppCoversFullScreenWithPipOnDisplay() { + testSpec.assertLayersStart { + hasVisibleRegion(testApp.defaultWindowName, displayBounds) + coversAtMostRegion(displayBounds, pipApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun pipAppCoversFullScreen() { + testSpec.assertLayersEnd { + hasVisibleRegion(pipApp.defaultWindowName, displayBounds) + } + } + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index ff31ba7d2c01..e1fbc16e8ce2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -16,11 +16,15 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible @@ -30,6 +34,7 @@ import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.startRotation import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -40,58 +45,71 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class EnterPipTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec = getTransition(eachRun = true, - stringExtras = emptyMap()) { configuration -> - transitions { - pipApp.clickEnterPipButton() - pipApp.expandPipWindow(wmHelper) - } - assertions { - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() +class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = true, stringExtras = emptyMap()) { + transitions { + pipApp.clickEnterPipButton() + pipApp.expandPipWindow(wmHelper) + } + } - all("pipWindowBecomesVisible") { - this.showsAppWindow(pipApp.defaultWindowName) - } - } + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - layersTrace { - statusBarLayerIsAlwaysVisible() - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - layersTrace { - all("pipLayerBecomesVisible") { - this.showsLayer(pipApp.launcherName) - } - } - } + @Presubmit + @Test + fun pipWindowBecomesVisible() { + testSpec.assertWm { + this.showsAppWindow(pipApp.defaultWindowName) + } + } - flaky { - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0, bugId = 140855415) - } - } - } - } + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) + @Presubmit + @Test + fun pipLayerBecomesVisible() { + testSpec.assertLayers { + this.showsLayer(pipApp.launcherName) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + + @FlakyTest(bugId = 140855415) + @Test + fun noUncoveredRegions() = + testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt index eaaa2f6390be..215b97bfeb83 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -16,22 +16,27 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE -import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -42,82 +47,108 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class EnterPipToOtherOrientationTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - private val testApp = FixedAppHelper(instrumentation) + testSpec: FlickerTestParameter +) : PipTransition(testSpec) { + private val testApp = FixedAppHelper(instrumentation) + private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) + private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) { configuration -> - setupAndTeardown(this, configuration) + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + setupAndTeardown(this, configuration) - setup { - eachRun { - // Launch a portrait only app on the fullscreen stack - testApp.launchViaIntent(wmHelper, stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())) - // Launch the PiP activity fixed as landscape - pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())) - } + setup { + eachRun { + // Launch a portrait only app on the fullscreen stack + testApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())) + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())) } - teardown { - eachRun { - pipApp.exit() - testApp.exit() - } - } - transitions { - // Enter PiP, and assert that the PiP is within bounds now that the device is back - // in portrait - broadcastActionTrigger.doAction(ACTION_ENTER_PIP) - wmHelper.waitPipWindowShown() - wmHelper.waitForAppTransitionIdle() + } + teardown { + eachRun { + pipApp.exit(wmHelper) + testApp.exit(wmHelper) } - assertions { - val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + } + transitions { + // Enter PiP, and assert that the PiP is within bounds now that the device is back + // in portrait + broadcastActionTrigger.doAction(ACTION_ENTER_PIP) + wmHelper.waitPipWindowShown() + wmHelper.waitForAppTransitionIdle() + } + } - presubmit { - windowManagerTrace { - all("pipApp window is always on top") { - showsAppWindowOnTop(pipApp.defaultWindowName) - } - start("pipApp window hides testApp") { - isInvisible(testApp.defaultWindowName) - } - end("testApp windows is shown") { - isVisible(testApp.defaultWindowName) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } + @Presubmit + @Test + fun pipAppWindowIsAlwaysOnTop() { + testSpec.assertWm { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + } - layersTrace { - start("pipApp layer hides testApp") { - hasVisibleRegion(pipApp.defaultWindowName, startingBounds) - isInvisible(testApp.defaultWindowName) - } - } - } + @Presubmit + @Test + fun pipAppHidesTestApp() { + testSpec.assertWmStart { + isInvisible(testApp.defaultWindowName) + } + } - flaky { - layersTrace { - end("testApp layer covers fullscreen") { - hasVisibleRegion(testApp.defaultWindowName, endingBounds) - } - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - } - } - } - } + @Presubmit + @Test + fun testAppWindowIsVisible() { + testSpec.assertWmEnd { + isVisible(testApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun pipAppLayerHidesTestApp() { + testSpec.assertLayersStart { + hasVisibleRegion(pipApp.defaultWindowName, startingBounds) + isInvisible(testApp.defaultWindowName) + } + } + + @FlakyTest + @Test + fun testAppLayerCoversFullScreen() { + testSpec.assertLayersEnd { + hasVisibleRegion(testApp.defaultWindowName, endingBounds) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index f054e6412080..f3b9ea1455ca 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -16,17 +16,21 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.startRotation import com.android.wm.shell.flicker.IME_WINDOW_NAME import com.android.wm.shell.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -37,58 +41,67 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipKeyboardTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - private const val TAG_IME_VISIBLE = "imeIsVisible" +class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + private val imeApp = ImeAppHelper(instrumentation) - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val imeApp = ImeAppHelper(instrumentation) - val testSpec = getTransition(eachRun = false) { configuration -> - setup { - test { - imeApp.launchViaIntent(wmHelper) - setRotation(configuration.startRotation) - } + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = false) { configuration -> + setup { + test { + imeApp.launchViaIntent(wmHelper) + setRotation(configuration.startRotation) } - teardown { - test { - imeApp.exit() - setRotation(Surface.ROTATION_0) - } + } + teardown { + test { + imeApp.exit(wmHelper) + setRotation(Surface.ROTATION_0) } - transitions { - // open the soft keyboard - imeApp.openIME(wmHelper) - createTag(TAG_IME_VISIBLE) + } + transitions { + // open the soft keyboard + imeApp.openIME(wmHelper) + createTag(TAG_IME_VISIBLE) - // then close it again - imeApp.closeIME(wmHelper) - } - assertions { - presubmit { - windowManagerTrace { - // Ensure the pip window remains visible throughout - // any keyboard interactions - all("pipInVisibleBounds") { - val displayBounds = WindowUtils.getDisplayBounds( - configuration.startRotation) - coversAtMostRegion(pipApp.defaultWindowName, displayBounds) - } - // Ensure that the pip window does not obscure the keyboard - tag(TAG_IME_VISIBLE) { - isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName) - } - } - } - } + // then close it again + imeApp.closeIME(wmHelper) } + } + + /** + * Ensure the pip window remains visible throughout any keyboard interactions + */ + @Presubmit + @Test + fun pipInVisibleBounds() { + testSpec.assertWm { + val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + } + + /** + * Ensure that the pip window does not obscure the keyboard + */ + @Presubmit + @Test + fun pipIsAboveAppWindow() { + testSpec.assertWmTag(TAG_IME_VISIBLE) { + isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName) + } + } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 5) + companion object { + private const val TAG_IME_VISIBLE = "imeIsVisible" + + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt index 5a1e5a1fe7c5..daf381ee9ddb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt @@ -16,21 +16,25 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Postsubmit import android.view.Surface import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.dsl.runFlicker +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.exitSplitScreen -import com.android.server.wm.flicker.helpers.isInSplitScreen import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.helpers.ImeAppHelper import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.android.wm.shell.flicker.helpers.PipAppHelper -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.repetitions +import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.wm.shell.flicker.removeAllTasksButHome import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP @@ -46,83 +50,103 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 161435597) -class PipLegacySplitScreenTest( - rotationName: String, - rotation: Int -) : AppTestBase(rotationName, rotation) { - private val pipApp = PipAppHelper(instrumentation) +class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val imeApp = ImeAppHelper(instrumentation) private val testApp = FixedAppHelper(instrumentation) + private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) - @Test - fun testShowsPipLaunchingToSplitScreen() { - runFlicker(instrumentation) { - withTestName { "testShowsPipLaunchingToSplitScreen" } - repeat { TEST_REPETITIONS } + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } setup { test { removeAllTasksButHome() device.wakeUpAndGoToHomeScreen() - pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true")) - waitForAnimationComplete() + pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"), + wmHelper = wmHelper) } } transitions { - testApp.launchViaIntent() + testApp.launchViaIntent(wmHelper) device.launchSplitScreen(wmHelper) - imeApp.launchViaIntent() - waitForAnimationComplete() + imeApp.launchViaIntent(wmHelper) } teardown { eachRun { - imeApp.exit() - if (device.isInSplitScreen()) { - device.exitSplitScreen() - } - testApp.exit() + imeApp.exit(wmHelper) + testApp.exit(wmHelper) } test { removeAllTasksButHome() } } - assertions { - val displayBounds = WindowUtils.getDisplayBounds(rotation) - windowManagerTrace { - all("PIP window must remain inside visible bounds") { - coversAtMostRegion(pipApp.defaultWindowName, displayBounds) - } - end("Both app windows should be visible") { - isVisible(testApp.defaultWindowName) - isVisible(imeApp.defaultWindowName) - noWindowsOverlap(setOf(testApp.defaultWindowName, imeApp.defaultWindowName)) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - all("PIP layer must remain inside visible bounds") { - coversAtMostRegion(displayBounds, pipApp.defaultWindowName) - } - end("Both app layers should be visible") { - coversAtMostRegion(displayBounds, testApp.defaultWindowName) - coversAtMostRegion(displayBounds, imeApp.defaultWindowName) - } - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - } - } + } + + @Postsubmit + @Test + fun pipWindowInsideDisplayBounds() { + testSpec.assertWm { + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + } + + @Postsubmit + @Test + fun bothAppWindowsVisible() { + testSpec.assertWmEnd { + isVisible(testApp.defaultWindowName) + isVisible(imeApp.defaultWindowName) + noWindowsOverlap(setOf(testApp.defaultWindowName, imeApp.defaultWindowName)) + } + } + + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun pipLayerInsideDisplayBounds() { + testSpec.assertLayers { + coversAtMostRegion(displayBounds, pipApp.defaultWindowName) + } + } + + @Postsubmit + @Test + fun bothAppLayersVisible() { + testSpec.assertLayersEnd { + coversAtMostRegion(displayBounds, testApp.defaultWindowName) + coversAtMostRegion(displayBounds, imeApp.defaultWindowName) } } + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + companion object { const val TEST_REPETITIONS = 2 + @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val supportedRotations = intArrayOf(Surface.ROTATION_0) - return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( + supportedRotations = listOf(Surface.ROTATION_0), + repetitions = TEST_REPETITIONS + ) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt index ade65ac8aa63..43c12acef9e8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -16,11 +16,15 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation @@ -34,6 +38,7 @@ import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.statusBarLayerRotatesScales import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -44,73 +49,91 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipRotationTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val fixedApp = FixedAppHelper(instrumentation) - val testSpec = getTransition(eachRun = false) { configuration -> - setup { - test { - fixedApp.launchViaIntent(wmHelper) - } - eachRun { - setRotation(configuration.startRotation) - } +class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + private val fixedApp = FixedAppHelper(instrumentation) + private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation) + + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = false) { configuration -> + setup { + test { + fixedApp.launchViaIntent(wmHelper) } - transitions { - setRotation(configuration.endRotation) + eachRun { + setRotation(configuration.startRotation) } - teardown { - eachRun { - setRotation(Surface.ROTATION_0) - } + } + transitions { + setRotation(configuration.endRotation) + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) } - assertions { - val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation) - val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation) + } + } - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - layersTrace { - noUncoveredRegions(configuration.startRotation, - configuration.endRotation, allStates = false) - } - } + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - flaky { - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - navBarLayerRotatesAndScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) - statusBarLayerRotatesScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + testSpec.config.endRotation, allStates = false) - start("appLayerRotates_StartingBounds", bugId = 140855415) { - hasVisibleRegion(fixedApp.defaultWindowName, startingBounds) - coversAtMostRegion(startingBounds, pipApp.defaultWindowName) - } - end("appLayerRotates_EndingBounds", bugId = 140855415) { - hasVisibleRegion(fixedApp.defaultWindowName, endingBounds) - coversAtMostRegion(endingBounds, pipApp.defaultWindowName) - } - } - } - } - } + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - return FlickerTestRunnerFactory.getInstance().buildRotationTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, + testSpec.config.endRotation) + + @FlakyTest(bugId = 140855415) + @Test + fun appLayerRotates_StartingBounds() { + testSpec.assertLayersStart { + hasVisibleRegion(fixedApp.defaultWindowName, startingBounds) + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun appLayerRotates_EndingBounds() { + testSpec.assertLayersEnd { + hasVisibleRegion(fixedApp.defaultWindowName, endingBounds) + coversAtMostRegion(endingBounds, pipApp.defaultWindowName) + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigRotationTests( + supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt index 96b6c912d152..7ba085d3cf1a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt @@ -16,13 +16,14 @@ package com.android.wm.shell.flicker.pip +import com.android.wm.shell.flicker.FlickerTestBase import com.android.wm.shell.flicker.helpers.PipAppHelper import org.junit.Before abstract class PipTestBase( rotationName: String, rotation: Int -) : AppTestBase(rotationName, rotation) { +) : FlickerTestBase(rotationName, rotation) { protected val testApp = PipAppHelper(instrumentation) @Before diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt index f2d58997d1f2..02389a9ccf87 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt @@ -16,11 +16,15 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -32,6 +36,7 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -42,73 +47,89 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipToAppTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec = getTransition(eachRun = true) { configuration -> - setup { - eachRun { - this.setRotation(configuration.startRotation) - } - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } +class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = true) { configuration -> + setup { + eachRun { + this.setRotation(configuration.startRotation) } - transitions { - pipApp.expandPipWindowToApp(wmHelper) + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) } - assertions { - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() + } + transitions { + pipApp.expandPipWindowToApp(wmHelper) + } + } - all("appReplacesPipWindow") { - this.showsAppWindow(PIP_WINDOW_TITLE) - .then() - .showsAppWindowOnTop(pipApp.launcherName) - } - } + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() - layersTrace { - statusBarLayerIsAlwaysVisible() - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - all("appReplacesPipLayer") { - this.showsLayer(PIP_WINDOW_TITLE) - .then() - .showsLayer(pipApp.launcherName) - } - } - } + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - flaky { - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0, bugId = 140855415) - } + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - eventLog { - focusChanges( - "NexusLauncherActivity", pipApp.launcherName, - "NexusLauncherActivity", bugId = 151179149) - } - } - } - } + @Presubmit + @Test + fun appReplacesPipWindow() { + testSpec.assertWm { + this.showsAppWindow(PIP_WINDOW_TITLE) + .then() + .showsAppWindowOnTop(pipApp.launcherName) + } + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + + @Presubmit + @Test + fun appReplacesPipLayer() { + testSpec.assertLayers { + this.showsLayer(PIP_WINDOW_TITLE) + .then() + .showsLayer(pipApp.launcherName) + } + } - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) + @FlakyTest + @Test + fun noUncoveredRegions() = + testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + + @FlakyTest(bugId = 151179149) + @Test + fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", + pipApp.launcherName, "NexusLauncherActivity") + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt index 1b44377425db..968a11de2511 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt @@ -16,15 +16,19 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.startRotation @@ -32,6 +36,7 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -42,74 +47,88 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipToHomeTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): List<Array<Any>> { - val testSpec = getTransition(eachRun = true) { configuration -> - setup { - eachRun { - this.setRotation(configuration.startRotation) - } - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } +class PipToHomeTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = buildTransition(eachRun = true) { configuration -> + setup { + eachRun { + this.setRotation(configuration.startRotation) } - transitions { - pipApp.closePipWindow(wmHelper) + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) } - assertions { - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() + } + transitions { + pipApp.closePipWindow(wmHelper) + } + } - all("pipWindowBecomesInvisible") { - this.showsAppWindow(PIP_WINDOW_TITLE) - .then() - .hidesAppWindow(PIP_WINDOW_TITLE) - } - } + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() - layersTrace { - statusBarLayerIsAlwaysVisible() - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - all("pipLayerBecomesInvisible") { - this.showsLayer(PIP_WINDOW_TITLE) - .then() - .hidesLayer(PIP_WINDOW_TITLE) - } - } - } + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - postsubmit { - layersTrace { - navBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - } - } + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - flaky { - eventLog { - focusChanges(pipApp.launcherName, "NexusLauncherActivity", - bugId = 151179149) - } - } - } - } + @Presubmit + @Test + fun pipWindowBecomesInvisible() { + testSpec.assertWm { + this.showsAppWindow(PIP_WINDOW_TITLE) + .then() + .hidesAppWindow(PIP_WINDOW_TITLE) + } + } + + @Presubmit + @Test + fun pipLayerBecomesInvisible() { + testSpec.assertLayers { + this.showsLayer(PIP_WINDOW_TITLE) + .then() + .hidesLayer(PIP_WINDOW_TITLE) + } + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) + @Postsubmit + @Test + fun noUncoveredRegions() = + testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + + @Postsubmit + @Test + fun navBarLayerRotatesAndScales() = + testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + + @FlakyTest(bugId = 151179149) + @Test + fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity") + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt index b1e404e4c8e6..a94483ec00a0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt @@ -20,16 +20,26 @@ import android.app.Instrumentation import android.content.Intent import android.os.Bundle import android.view.Surface +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.buildTestTag +import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.repetitions +import com.android.server.wm.flicker.startRotation import com.android.wm.shell.flicker.helpers.PipAppHelper import com.android.wm.shell.flicker.removeAllTasksButHome import com.android.wm.shell.flicker.testapp.Components -abstract class PipTransitionBase(protected val instrumentation: Instrumentation) { +abstract class PipTransition(protected val testSpec: FlickerTestParameter) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected val isRotated = testSpec.config.startRotation.isRotated() + protected val pipApp = PipAppHelper(instrumentation) + protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) + protected abstract val transition: FlickerBuilder.(Bundle) -> Unit + // Helper class to process test actions by broadcast. protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) { private fun createIntentWithAction(broadcastAction: String): Intent { @@ -59,16 +69,20 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation) } } - protected val pipApp = PipAppHelper(instrumentation) - protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + transition(this, testSpec.config) + } + } /** * Gets a configuration that handles basic setup and teardown of pip tests */ protected val setupAndTeardown: FlickerBuilder.(Bundle) -> Unit - get() = { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } + get() = { setup { test { removeAllTasksButHome() @@ -81,7 +95,7 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation) } test { removeAllTasksButHome() - pipApp.exit() + pipApp.exit(wmHelper) } } } @@ -95,7 +109,7 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation) * @param extraSpec Addicional segment of flicker specification */ @JvmOverloads - open fun getTransition( + protected open fun buildTransition( eachRun: Boolean, stringExtras: Map<String, String> = mapOf(Components.PipActivity.EXTRA_ENTER_PIP to "true"), extraSpec: FlickerBuilder.(Bundle) -> Unit = {} @@ -121,12 +135,12 @@ abstract class PipTransitionBase(protected val instrumentation: Instrumentation) teardown { eachRun { if (eachRun) { - pipApp.exit() + pipApp.exit(wmHelper) } } test { if (!eachRun) { - pipApp.exit() + pipApp.exit(wmHelper) } removeAllTasksButHome() } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt index c01bc94151e9..1f0370dc0505 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -16,21 +16,26 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP import org.junit.Assert.assertEquals import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -41,75 +46,99 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class SetRequestedOrientationWhilePinnedTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 1) { configuration -> - setupAndTeardown(this, configuration) + testSpec: FlickerTestParameter +) : PipTransition(testSpec) { + private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - setup { - eachRun { - // Launch the PiP activity fixed as landscape - pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(), - EXTRA_ENTER_PIP to "true")) - } - } - teardown { - eachRun { - pipApp.exit() - } - } - transitions { - // Request that the orientation is set to landscape - broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE) + override val transition: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + setupAndTeardown(this, configuration) - // Launch the activity back into fullscreen and - // ensure that it is now in landscape - pipApp.launchViaIntent(wmHelper) - wmHelper.waitForFullScreenApp(pipApp.component) - wmHelper.waitForRotation(Surface.ROTATION_90) - assertEquals(Surface.ROTATION_90, device.displayRotation) + setup { + eachRun { + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(), + EXTRA_ENTER_PIP to "true")) } - assertions { - val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) - val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - presubmit { - windowManagerTrace { - start("PIP window must remain inside display") { - coversAtMostRegion(pipApp.defaultWindowName, startingBounds) - } - end("pipApp shows on top") { - showsAppWindowOnTop(pipApp.defaultWindowName) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - start("PIP layer must remain inside display") { - coversAtMostRegion(startingBounds, pipApp.defaultWindowName) - } - end("pipApp layer covers fullscreen") { - hasVisibleRegion(pipApp.defaultWindowName, endingBounds) - } - } - } - - flaky { - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - } - } + } + teardown { + eachRun { + pipApp.exit(wmHelper) } } + transitions { + // Request that the orientation is set to landscape + broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE) + + // Launch the activity back into fullscreen and + // ensure that it is now in landscape + pipApp.launchViaIntent(wmHelper) + wmHelper.waitForFullScreenApp(pipApp.component) + wmHelper.waitForRotation(Surface.ROTATION_90) + assertEquals(Surface.ROTATION_90, device.displayRotation) + } + } + + @Presubmit + @Test + fun pipWindowInsideDisplay() { + testSpec.assertWmStart { + coversAtMostRegion(pipApp.defaultWindowName, startingBounds) + } + } + + @Presubmit + @Test + fun pipAppShowsOnTop() { + testSpec.assertWmEnd { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun pipLayerInsideDisplay() { + testSpec.assertLayersStart { + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) + } + } + + @Presubmit + @Test + fun pipAppLayerCoversFullScreen() { + testSpec.assertLayersEnd { + hasVisibleRegion(pipApp.defaultWindowName, endingBounds) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 1) } } -}
\ No newline at end of file +} diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING index 777aa0b429e5..766714cd7694 100644 --- a/libs/androidfw/TEST_MAPPING +++ b/libs/androidfw/TEST_MAPPING @@ -1,10 +1,6 @@ { "presubmit": [ { - "name": "libandroidfw_tests", - "host": true - }, - { "name": "CtsResourcesLoaderTests" } ] diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index 2cd9b7b39174..b570af5a0c93 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -112,7 +112,7 @@ void JankTracker::finishFrame(const FrameInfo& frame) { std::lock_guard lock(mDataMutex); // Fast-path for jank-free frames - int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted); + int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::SwapBuffersCompleted); if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) { nsecs_t expectedDequeueDuration = mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync] - frame[FrameInfoIndex::IssueDrawCommandsStart]; diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 1fddac4cd05d..28d2b4cec0e1 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -188,7 +188,7 @@ void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) { } if (mCanvas->getSaveCount() == restoreCount + 1) { - SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint)); + SkCanvasPriv::DrawBehind(mCanvas, filterPaint(paint)); this->restore(); } } @@ -431,15 +431,14 @@ void SkiaCanvas::drawColor(int color, SkBlendMode mode) { mCanvas->drawColor(color, mode); } -SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const { +void SkiaCanvas::onFilterPaint(SkPaint& paint) { if (mPaintFilter) { - mPaintFilter->filter(&paint.writeable()); + mPaintFilter->filter(&paint); } - return std::move(paint); } void SkiaCanvas::drawPaint(const SkPaint& paint) { - mCanvas->drawPaint(*filterPaint(paint)); + mCanvas->drawPaint(filterPaint(paint)); } // ---------------------------------------------------------------------------- @@ -457,13 +456,11 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint, points += 2; } - apply_looper(&paint, [&](const SkPaint& p) { - mCanvas->drawPoints(mode, count, pts.get(), p); - }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoints(mode, count, pts.get(), p); }); } void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) { - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); }); } void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) { @@ -472,9 +469,8 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, const Paint& paint) { - apply_looper(&paint, [&](const SkPaint& p) { - mCanvas->drawLine(startX, startY, stopX, stopY, p); - }); + applyLooper(&paint, + [&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); }); } void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) { @@ -484,46 +480,44 @@ void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) { void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; - apply_looper(&paint, [&](const SkPaint& p) { + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRect({left, top, right, bottom}, p); }); } void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); }); } void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, const Paint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - apply_looper(&paint, [&](const SkPaint& p) { - mCanvas->drawRoundRect(rect, rx, ry, p); - }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); }); } void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner, const Paint& paint) { - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); }); } void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) { if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return; - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); }); } void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); }); } void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, bool useCenter, const Paint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); - apply_looper(&paint, [&](const SkPaint& p) { + applyLooper(&paint, [&](const SkPaint& p) { if (fabs(sweepAngle) >= 360.0f) { mCanvas->drawOval(arc, p); } else { @@ -537,13 +531,11 @@ void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) { if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) { return; } - apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); }); } void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) { - apply_looper(&paint, [&](const SkPaint& p) { - mCanvas->drawVertices(vertices, mode, p); - }); + applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); }); } // ---------------------------------------------------------------------------- @@ -552,7 +544,7 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) { auto image = bitmap.makeImage(); - apply_looper(paint, [&](const SkPaint& p) { + applyLooper(paint, [&](const SkPaint& p) { auto sampling = SkSamplingOptions(p.getFilterQuality()); mCanvas->drawImage(image, left, top, sampling, &p); }); @@ -562,7 +554,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* auto image = bitmap.makeImage(); SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - apply_looper(paint, [&](const SkPaint& p) { + applyLooper(paint, [&](const SkPaint& p) { auto sampling = SkSamplingOptions(p.getFilterQuality()); mCanvas->drawImage(image, 0, 0, sampling, &p); }); @@ -575,7 +567,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - apply_looper(paint, [&](const SkPaint& p) { + applyLooper(paint, [&](const SkPaint& p) { auto sampling = SkSamplingOptions(p.getFilterQuality()); mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p, SkCanvas::kFast_SrcRectConstraint); @@ -672,11 +664,11 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, pnt.setShader(image->makeShader(sampling)); auto v = builder.detach(); - apply_looper(&pnt, [&](const SkPaint& p) { + applyLooper(&pnt, [&](const SkPaint& p) { SkPaint copy(p); auto s = SkSamplingOptions(p.getFilterQuality()); if (s != sampling) { - // apply_looper changed the quality? + // applyLooper changed the quality? copy.setShader(image->makeShader(s)); } mCanvas->drawVertices(v, SkBlendMode::kModulate, copy); @@ -707,7 +699,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); auto image = bitmap.makeImage(); - apply_looper(paint, [&](const SkPaint& p) { + applyLooper(paint, [&](const SkPaint& p) { auto filter = SkSamplingOptions(p.getFilterQuality()).filter; mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p); }); @@ -746,9 +738,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& pai sk_sp<SkTextBlob> textBlob(builder.make()); - apply_looper(&paintCopy, [&](const SkPaint& p) { - mCanvas->drawTextBlob(textBlob, 0, 0, p); - }); + applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); }); drawTextDecorations(x, y, totalAdvance, paintCopy); } @@ -788,9 +778,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, sk_sp<SkTextBlob> textBlob(builder.make()); - apply_looper(&paintCopy, [&](const SkPaint& p) { - mCanvas->drawTextBlob(textBlob, 0, 0, p); - }); + applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); }); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index eac3f2217bd8..9ab2b106dbfa 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -169,53 +169,24 @@ protected: const Paint& paint, const SkPath& path, size_t start, size_t end) override; - /** This class acts as a copy on write SkPaint. - * - * Initially this will be the SkPaint passed to the contructor. - * The first time writable() is called this will become a copy of the - * initial SkPaint (or a default SkPaint if nullptr). - */ - struct PaintCoW { - PaintCoW(const SkPaint& that) : mPtr(&that) {} - PaintCoW(const SkPaint* ptr) : mPtr(ptr) {} - PaintCoW(const PaintCoW&) = delete; - PaintCoW(PaintCoW&&) = delete; - PaintCoW& operator=(const PaintCoW&) = delete; - PaintCoW& operator=(PaintCoW&&) = delete; - SkPaint& writeable() { - if (!mStorage) { - if (!mPtr) { - mStorage.emplace(); - } else { - mStorage.emplace(*mPtr); - } - mPtr = &*mStorage; - } - return *mStorage; - } - operator const SkPaint*() const { return mPtr; } - const SkPaint* operator->() const { assert(mPtr); return mPtr; } - explicit operator bool() { return mPtr != nullptr; } - private: - const SkPaint* mPtr; - std::optional<SkPaint> mStorage; - }; + void onFilterPaint(SkPaint& paint); - /** Filters the paint using the current paint filter. - * - * @param paint the paint to filter. Will be initialized with the default - * SkPaint before filtering if filtering is required. - */ - PaintCoW&& filterPaint(PaintCoW&& paint) const; + SkPaint filterPaint(const SkPaint& src) { + SkPaint dst(src); + this->onFilterPaint(dst); + return dst; + } // proc(const SkPaint& modifiedPaint) - template <typename Proc> void apply_looper(const Paint* paint, Proc proc) { - SkPaint skp; - BlurDrawLooper* looper = nullptr; - if (paint) { - skp = *filterPaint(paint); - looper = paint->getLooper(); + template <typename Proc> + void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) { + BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr; + const SkPaint* skpPtr = paint; + SkPaint skp = skpPtr ? *skpPtr : SkPaint(); + if (preFilter) { + preFilter(skp); } + this->onFilterPaint(skp); if (looper) { looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) { mCanvas->save(); @@ -228,7 +199,6 @@ protected: } } - private: struct SaveRec { int saveCount; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 04e3a1cb887e..af7271e96cb9 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -170,36 +170,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { // Recording Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) { - bool fixBlending = false; - bool fixAA = false; - if (paint) { - // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and - // older. - fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear; - fixAA = paint->isAntiAlias(); +void SkiaRecordingCanvas::FilterForImage(SkPaint& paint) { + // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and + // older. + if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) { + paint.setBlendMode(SkBlendMode::kDstOut); } - if (fixBlending || fixAA) { - SkPaint& tmpPaint = paint.writeable(); - - if (fixBlending) { - tmpPaint.setBlendMode(SkBlendMode::kDstOut); - } - - // disabling AA on bitmap draws matches legacy HWUI behavior - tmpPaint.setAntiAlias(false); - } - - return filterPaint(std::move(paint)); + // disabling AA on bitmap draws matches legacy HWUI behavior + paint.setAntiAlias(false); } -static SkFilterMode Paint_to_filter(const SkPaint* paint) { - return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear - : SkFilterMode::kNearest; +static SkFilterMode Paint_to_filter(const SkPaint& paint) { + return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear + : SkFilterMode::kNearest; } -static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) { +static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) { // Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone); } @@ -207,9 +194,12 @@ static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) { void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) { sk_sp<SkImage> image = bitmap.makeImage(); - applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) { - mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette()); - }); + applyLooper( + paint, + [&](const SkPaint& p) { + mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette()); + }, + FilterForImage); // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means // it is not safe to store a raw SkImage pointer, because the image object will be destroyed @@ -225,9 +215,12 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con sk_sp<SkImage> image = bitmap.makeImage(); - applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) { - mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette()); - }); + applyLooper( + paint, + [&](const SkPaint& p) { + mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette()); + }, + FilterForImage); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); @@ -242,10 +235,13 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop sk_sp<SkImage> image = bitmap.makeImage(); - applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) { - mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p), - p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); - }); + applyLooper( + paint, + [&](const SkPaint& p) { + mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p, + SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); + }, + FilterForImage); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { @@ -281,10 +277,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch // HWUI always draws 9-patches with linear filtering, regardless of the Paint. const SkFilterMode filter = SkFilterMode::kLinear; - applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) { - mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p, - bitmap.palette()); - }); + applyLooper( + paint, + [&](const SkPaint& p) { + mRecorder.drawImageLattice(image, lattice, dst, filter, &p, bitmap.palette()); + }, + FilterForImage); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 1e404b845084..ff03e0c5f6d6 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -87,22 +87,7 @@ private: std::unique_ptr<SkiaDisplayList> mDisplayList; StartReorderBarrierDrawable* mCurrentBarrier; - template <typename Proc> - void applyLooper(const Paint* paint, Proc proc) { - SkPaint skp; - BlurDrawLooper* looper = nullptr; - if (paint) { - skp = *filterBitmap(paint); - looper = paint->getLooper(); - } - if (looper) { - looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) { - proc(offset.fX, offset.fY, &modifiedPaint); - }); - } else { - proc(0, 0, &skp); - } - } + static void FilterForImage(SkPaint&); /** * A new SkiaDisplayList is created or recycled if available. @@ -113,7 +98,7 @@ private: */ void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height); - PaintCoW&& filterBitmap(PaintCoW&& paint); + using INHERITED = SkiaCanvas; }; } // namespace skiapipeline diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index adf58da6a072..5e3966032a11 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -48,13 +48,13 @@ import android.os.ICancellationSignal; */ interface ILocationManager { - @nullable Location getLastLocation(String provider, in LastLocationRequest request, String packageName, String attributionTag); - @nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, String attributionTag, String listenerId); + @nullable Location getLastLocation(String provider, in LastLocationRequest request, String packageName, @nullable String attributionTag); + @nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, @nullable String attributionTag, String listenerId); - void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId); + void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, @nullable String attributionTag, String listenerId); void unregisterLocationListener(in ILocationListener listener); - void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, String attributionTag); + void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, @nullable String attributionTag); void unregisterLocationPendingIntent(in PendingIntent pendingIntent); void injectLocation(in Location location); @@ -79,24 +79,24 @@ interface ILocationManager @nullable List<GnssAntennaInfo> getGnssAntennaInfos(); - void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, @nullable String attributionTag); + void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, @nullable String attributionTag, String listenerId); void unregisterGnssStatusCallback(in IGnssStatusListener callback); - void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, @nullable String attributionTag); + void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, @nullable String attributionTag, String listenerId); void unregisterGnssNmeaCallback(in IGnssNmeaListener callback); - void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, @nullable String attributionTag); + void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, @nullable String attributionTag, String listenerId); void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener); void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections); - void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag); + void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag, String listenerId); void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener); void addProviderRequestListener(in IProviderRequestListener listener); void removeProviderRequestListener(in IProviderRequestListener listener); int getGnssBatchSize(); - void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, @nullable String listenerId); + void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, String listenerId); void flushGnssBatch(); void stopGnssBatch(); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index b7823400695d..dd5b6e6b4222 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -51,7 +51,7 @@ import android.content.pm.PackageManager; import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; -import android.location.provider.ProviderRequest.Listener; +import android.location.provider.ProviderRequest.ChangedListener; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -2779,33 +2779,32 @@ public class LocationManager { } /** - * Registers a {@link ProviderRequest.Listener} to all providers. + * Adds a {@link ProviderRequest.ChangedListener} for listening to all providers' + * {@link ProviderRequest} changed events. * * @param executor the executor that the callback runs on * @param listener the listener to register - * @return {@code true} always * @hide */ @SystemApi @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) - public boolean registerProviderRequestListener( + public void addProviderRequestChangedListener( @NonNull @CallbackExecutor Executor executor, - @NonNull Listener listener) { + @NonNull ChangedListener listener) { ProviderRequestLazyLoader.sProviderRequestListeners.addListener(listener, new ProviderRequestTransport(executor, listener)); - return true; } /** - * Unregisters a {@link ProviderRequest.Listener}. + * Removes a {@link ProviderRequest.ChangedListener} that has been added. * * @param listener the listener to remove. * @hide */ @SystemApi @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) - public void unregisterProviderRequestListener( - @NonNull Listener listener) { + public void removeProviderRequestChangedListener( + @NonNull ProviderRequest.ChangedListener listener) { ProviderRequestLazyLoader.sProviderRequestListeners.removeListener(listener); } @@ -2926,7 +2925,8 @@ public class LocationManager { protected void registerTransport(GnssStatusTransport transport) throws RemoteException { getService().registerGnssStatusCallback(transport, transport.getPackage(), - transport.getAttributionTag()); + transport.getAttributionTag(), + AppOpsManager.toReceiverId(transport.getListener())); } @Override @@ -2947,7 +2947,8 @@ public class LocationManager { protected void registerTransport(GnssNmeaTransport transport) throws RemoteException { getService().registerGnssNmeaCallback(transport, transport.getPackage(), - transport.getAttributionTag()); + transport.getAttributionTag(), + AppOpsManager.toReceiverId(transport.getListener())); } @Override @@ -2968,7 +2969,8 @@ public class LocationManager { protected void registerTransport(GnssMeasurementsTransport transport) throws RemoteException { getService().addGnssMeasurementsListener(transport.getRequest(), transport, - transport.getPackage(), transport.getAttributionTag()); + transport.getPackage(), transport.getAttributionTag(), + AppOpsManager.toReceiverId(transport.getListener())); } @Override @@ -3008,7 +3010,8 @@ public class LocationManager { protected void registerTransport(GnssNavigationTransport transport) throws RemoteException { getService().addGnssNavigationMessageListener(transport, - transport.getPackage(), transport.getAttributionTag()); + transport.getPackage(), transport.getAttributionTag(), + AppOpsManager.toReceiverId(transport.getListener())); } @Override @@ -3442,13 +3445,13 @@ public class LocationManager { } private static class ProviderRequestTransport extends IProviderRequestListener.Stub - implements ListenerTransport<ProviderRequest.Listener> { + implements ListenerTransport<ChangedListener> { private final Executor mExecutor; - private volatile @Nullable ProviderRequest.Listener mListener; + private volatile @Nullable ProviderRequest.ChangedListener mListener; - ProviderRequestTransport(Executor executor, ProviderRequest.Listener listener) { + ProviderRequestTransport(Executor executor, ChangedListener listener) { Preconditions.checkArgument(executor != null, "invalid null executor"); Preconditions.checkArgument(listener != null, "invalid null callback"); mExecutor = executor; @@ -3461,7 +3464,7 @@ public class LocationManager { } @Override - public @Nullable ProviderRequest.Listener getListener() { + public @Nullable ProviderRequest.ChangedListener getListener() { return mListener; } diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java index b6ec32309b08..b72d36519e72 100644 --- a/location/java/android/location/provider/ProviderRequest.java +++ b/location/java/android/location/provider/ProviderRequest.java @@ -56,10 +56,13 @@ public final class ProviderRequest implements Parcelable { /** * Listener to be invoked when a new request is set to the provider. */ - public interface Listener { + public interface ChangedListener { /** * Invoked when a new request is set. + * + * @param provider the location provider associated with the request + * @param request the new {@link ProviderRequest} */ void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request); } diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java index 44f8385b715e..9ab4aac891e5 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -131,7 +131,59 @@ public class ImageWriter implements AutoCloseable { */ public static @NonNull ImageWriter newInstance(@NonNull Surface surface, @IntRange(from = 1) int maxImages) { - return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN); + return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN, -1 /*width*/, + -1 /*height*/); + } + + /** + * <p> + * Create a new ImageWriter with given number of max Images, format and producer dimension. + * </p> + * <p> + * The {@code maxImages} parameter determines the maximum number of + * {@link Image} objects that can be be dequeued from the + * {@code ImageWriter} simultaneously. Requesting more buffers will use up + * more memory, so it is important to use only the minimum number necessary. + * </p> + * <p> + * The format specifies the image format of this ImageWriter. The format + * from the {@code surface} will be overridden with this format. For example, + * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default + * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter + * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate + * with {@link ImageFormat#PRIVATE} Images. + * </p> + * <p> + * Note that the consumer end-point may or may not be able to support Images with different + * format, for such case, the application should only use this method if the consumer is able + * to consume such images. + * </p> + * <p> The input Image size can also be set by the client. </p> + * + * @param surface The destination Surface this writer produces Image data + * into. + * @param maxImages The maximum number of Images the user will want to + * access simultaneously for producing Image data. This should be + * as small as possible to limit memory use. Once maxImages + * Images are dequeued by the user, one of them has to be queued + * back before a new Image can be dequeued for access via + * {@link #dequeueInputImage()}. + * @param format The format of this ImageWriter. It can be any valid format specified by + * {@link ImageFormat} or {@link PixelFormat}. + * + * @param width Input size width. + * @param height Input size height. + * + * @return a new ImageWriter instance. + * + * @hide + */ + public static @NonNull ImageWriter newInstance(@NonNull Surface surface, + @IntRange(from = 1) int maxImages, @Format int format, int width, int height) { + if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { + throw new IllegalArgumentException("Invalid format is specified: " + format); + } + return new ImageWriter(surface, maxImages, format, width, height); } /** @@ -180,13 +232,13 @@ public class ImageWriter implements AutoCloseable { if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { throw new IllegalArgumentException("Invalid format is specified: " + format); } - return new ImageWriter(surface, maxImages, format); + return new ImageWriter(surface, maxImages, format, -1 /*width*/, -1 /*height*/); } /** * @hide */ - protected ImageWriter(Surface surface, int maxImages, int format) { + protected ImageWriter(Surface surface, int maxImages, int format, int width, int height) { if (surface == null || maxImages < 1) { throw new IllegalArgumentException("Illegal input argument: surface " + surface + ", maxImages: " + maxImages); @@ -196,7 +248,8 @@ public class ImageWriter implements AutoCloseable { // Note that the underlying BufferQueue is working in synchronous mode // to avoid dropping any buffers. - mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format); + mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format, width, + height); // nativeInit internally overrides UNKNOWN format. So does surface format query after // nativeInit and before getEstimatedNativeAllocBytes(). @@ -919,7 +972,7 @@ public class ImageWriter implements AutoCloseable { // Native implemented ImageWriter methods. private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs, - int format); + int format, int width, int height); private synchronized native void nativeClose(long nativeCtx); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index c51c9dd06c24..f3cee17ab238 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -19,6 +19,7 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -91,6 +92,7 @@ import java.util.Scanner; import java.util.Set; import java.util.UUID; import java.util.Vector; +import java.util.concurrent.Executor; /** @@ -2172,7 +2174,7 @@ public class MediaPlayer extends PlayerBase mOnVideoSizeChangedListener = null; mOnTimedTextListener = null; mOnRtpRxNoticeListener = null; - mOnRtpRxNoticeHandler = null; + mOnRtpRxNoticeExecutor = null; synchronized (mTimeProviderLock) { if (mTimeProvider != null) { mTimeProvider.close(); @@ -3711,7 +3713,6 @@ public class MediaPlayer extends PlayerBase case MEDIA_RTP_RX_NOTICE: final OnRtpRxNoticeListener rtpRxNoticeListener = mOnRtpRxNoticeListener; - final Handler rtpRxNoticeHandler = mOnRtpRxNoticeHandler; if (rtpRxNoticeListener == null) { return; } @@ -3730,14 +3731,9 @@ public class MediaPlayer extends PlayerBase } finally { parcel.recycle(); } - if (rtpRxNoticeHandler == null) { - rtpRxNoticeListener.onRtpRxNotice(mMediaPlayer, noticeType, data); - } else { - rtpRxNoticeHandler.post( - () -> - rtpRxNoticeListener - .onRtpRxNotice(mMediaPlayer, noticeType, data)); - } + mOnRtpRxNoticeExecutor.execute(() -> + rtpRxNoticeListener + .onRtpRxNotice(mMediaPlayer, noticeType, data)); } return; @@ -4305,28 +4301,26 @@ public class MediaPlayer extends PlayerBase * * @see OnRtpRxNoticeListener * - * @param listener the listener called after a notice from RTP Rx - * @param handler the {@link Handler} that receives RTP Tx events. If null is passed, - * notifications will be posted on the thread that created this MediaPlayer - * instance. If the creating thread does not have a {@link Looper}, then - * notifications will be posted on the main thread. + * @param listener the listener called after a notice from RTP Rx. + * @param executor the {@link Executor} on which to post RTP Tx events. * @hide */ @SystemApi @RequiresPermission(BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener( @NonNull Context context, - @NonNull OnRtpRxNoticeListener listener, @Nullable Handler handler) { + @NonNull @CallbackExecutor Executor executor, + @NonNull OnRtpRxNoticeListener listener) { Objects.requireNonNull(context); Preconditions.checkArgument( context.checkSelfPermission(BIND_IMS_SERVICE) == PERMISSION_GRANTED, BIND_IMS_SERVICE + " permission not granted."); mOnRtpRxNoticeListener = Objects.requireNonNull(listener); - mOnRtpRxNoticeHandler = handler; + mOnRtpRxNoticeExecutor = Objects.requireNonNull(executor); } private OnRtpRxNoticeListener mOnRtpRxNoticeListener; - private Handler mOnRtpRxNoticeHandler; + private Executor mOnRtpRxNoticeExecutor; /** * Register a callback to be invoked when a selected track has timed metadata available. diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 5d959a3930f4..b291ac95bf4f 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -364,7 +364,7 @@ static void ImageWriter_classInit(JNIEnv* env, jclass clazz) { } static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobject jsurface, - jint maxImages, jint userFormat) { + jint maxImages, jint userFormat, jint userWidth, jint userHeight) { status_t res; ALOGV("%s: maxImages:%d", __FUNCTION__, maxImages); @@ -405,20 +405,38 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje // Get the dimension and format of the producer. sp<ANativeWindow> anw = producer; int32_t width, height, surfaceFormat; - if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) { - ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res); - jniThrowRuntimeException(env, "Failed to query Surface width"); - return 0; + if (userWidth < 0) { + if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) { + ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res); + jniThrowRuntimeException(env, "Failed to query Surface width"); + return 0; + } + } else { + width = userWidth; } + ctx->setBufferWidth(width); - if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) { - ALOGE("%s: Query Surface height failed: %s (%d)", __FUNCTION__, strerror(-res), res); - jniThrowRuntimeException(env, "Failed to query Surface height"); - return 0; + if (userHeight < 0) { + if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) { + ALOGE("%s: Query Surface height failed: %s (%d)", __FUNCTION__, strerror(-res), res); + jniThrowRuntimeException(env, "Failed to query Surface height"); + return 0; + } + } else { + height = userHeight; } ctx->setBufferHeight(height); + if ((userWidth > 0) && (userHeight > 0)) { + res = native_window_set_buffers_user_dimensions(anw.get(), userWidth, userHeight); + if (res != OK) { + ALOGE("%s: Set buffer dimensions failed: %s (%d)", __FUNCTION__, strerror(-res), res); + jniThrowRuntimeException(env, "Set buffer dimensions failed"); + return 0; + } + } + // Query surface format if no valid user format is specified, otherwise, override surface format // with user format. if (userFormat == IMAGE_FORMAT_UNKNOWN) { @@ -1045,7 +1063,7 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, static JNINativeMethod gImageWriterMethods[] = { {"nativeClassInit", "()V", (void*)ImageWriter_classInit }, - {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;II)J", + {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;IIII)J", (void*)ImageWriter_init }, {"nativeClose", "(J)V", (void*)ImageWriter_close }, {"nativeAttachAndQueueImage", "(JJIJIIIIII)I", (void*)ImageWriter_attachAndQueueImage }, diff --git a/media/jni/android_media_JetPlayer.cpp b/media/jni/android_media_JetPlayer.cpp index 481f80b278f8..10a5b586c2b9 100644 --- a/media/jni/android_media_JetPlayer.cpp +++ b/media/jni/android_media_JetPlayer.cpp @@ -43,12 +43,34 @@ struct fields_t { jfieldID nativePlayerInJavaObj; // stores in Java the native JetPlayer object }; -static fields_t javaJetPlayerFields; +static fields_t javaJetPlayerFields {}; +#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj" +#define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative" + +static void initializeJavaIDs(JNIEnv* env) { + static std::once_flag sJniInitialized; + + std::call_once(sJniInitialized, [](JNIEnv* env) { + // Get the JetPlayer java class + jclass jetPlayerClass = FindClassOrDie(env, kClassPathName); + javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass); + + // Get the mNativePlayerInJavaObj variable field + javaJetPlayerFields.nativePlayerInJavaObj = + GetFieldIDOrDie(env, jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J"); + + // Get the callback to post events from this native code to Java + javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env, + javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, + "(Ljava/lang/Object;III)V"); + }, env); +} // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- + /* * This function is called from JetPlayer instance's render thread */ @@ -79,6 +101,8 @@ static jboolean android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this, jint maxTracks, jint trackBufferSize) { + initializeJavaIDs(env); + //ALOGV("android_media_JetPlayer_setup(): entering."); JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize); @@ -511,28 +535,9 @@ static const JNINativeMethod gMethods[] = { {"native_clearQueue", "()Z", (void *)android_media_JetPlayer_clearQueue}, }; -#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj" -#define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative" int register_android_media_JetPlayer(JNIEnv *env) { - javaJetPlayerFields.jetClass = NULL; - javaJetPlayerFields.postNativeEventInJava = NULL; - javaJetPlayerFields.nativePlayerInJavaObj = NULL; - - // Get the JetPlayer java class - jclass jetPlayerClass = FindClassOrDie(env, kClassPathName); - javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass); - - // Get the mNativePlayerInJavaObj variable field - javaJetPlayerFields.nativePlayerInJavaObj = GetFieldIDOrDie(env, - jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J"); - - // Get the callback to post events from this native code to Java - javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env, - javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, - "(Ljava/lang/Object;III)V"); - return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp index 517672ee6127..f491be884b2f 100644 --- a/media/jni/android_media_MediaCrypto.cpp +++ b/media/jni/android_media_MediaCrypto.cpp @@ -202,10 +202,11 @@ static void android_media_MediaCrypto_native_setup( uuid = NULL; if (err != OK) { - jniThrowException( + std::string strerr(StrCryptoError(err)); + jniThrowExceptionFmt( env, "android/media/MediaCryptoException", - "Failed to instantiate crypto object."); + "Failed to instantiate crypto object: %s", strerr.c_str()); return; } @@ -295,7 +296,8 @@ static void android_media_MediaCrypto_setMediaDrmSession( } else if (err == NO_INIT) { msg += ": crypto plugin not initialized"; } else { - msg.appendFormat(": general failure (%d)", err); + std::string strerr(StrCryptoError(err)); + msg.appendFormat(": general failure (%s)", strerr.c_str()); } jniThrowException(env, "android/media/MediaCryptoException", msg.string()); } diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index eee9f1e08131..177b00a573c3 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -217,23 +217,36 @@ namespace android { void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) { ALOGD("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mLnbObj, - gFields.onLnbEventID, - (jint)lnbEventType); + jobject lnb(env->NewLocalRef(mLnbObj)); + if (!env->IsSameObject(lnb, nullptr)) { + env->CallVoidMethod( + lnb, + gFields.onLnbEventID, + (jint)lnbEventType); + } else { + ALOGE("LnbClientCallbackImpl::onEvent:" + "Lnb object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mLnbObj); + } } void LnbClientCallbackImpl::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) { ALOGD("LnbClientCallbackImpl::onDiseqcMessage"); JNIEnv *env = AndroidRuntime::getJNIEnv(); - jbyteArray array = env->NewByteArray(diseqcMessage.size()); - env->SetByteArrayRegion( - array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0])); - - env->CallVoidMethod( - mLnbObj, - gFields.onLnbDiseqcMessageID, - array); + jobject lnb(env->NewLocalRef(mLnbObj)); + if (!env->IsSameObject(lnb, nullptr)) { + jbyteArray array = env->NewByteArray(diseqcMessage.size()); + env->SetByteArrayRegion( + array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0])); + env->CallVoidMethod( + lnb, + gFields.onLnbDiseqcMessageID, + array); + } else { + ALOGE("LnbClientCallbackImpl::onDiseqcMessage:" + "Lnb object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mLnbObj); + } } void LnbClientCallbackImpl::setLnb(jweak lnbObj) { @@ -254,19 +267,33 @@ LnbClientCallbackImpl::~LnbClientCallbackImpl() { void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) { ALOGD("DvrClientCallbackImpl::onRecordStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mDvrObj, - gFields.onDvrRecordStatusID, - (jint) status); + jobject dvr(env->NewLocalRef(mDvrObj)); + if (!env->IsSameObject(dvr, nullptr)) { + env->CallVoidMethod( + dvr, + gFields.onDvrRecordStatusID, + (jint) status); + } else { + ALOGE("DvrClientCallbackImpl::onRecordStatus:" + "Dvr object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mDvrObj); + } } void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) { ALOGD("DvrClientCallbackImpl::onPlaybackStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mDvrObj, - gFields.onDvrPlaybackStatusID, - (jint) status); + jobject dvr(env->NewLocalRef(mDvrObj)); + if (!env->IsSameObject(dvr, nullptr)) { + env->CallVoidMethod( + dvr, + gFields.onDvrPlaybackStatusID, + (jint) status); + } else { + ALOGE("DvrClientCallbackImpl::onPlaybackStatus:" + "Dvr object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mDvrObj); + } } void DvrClientCallbackImpl::setDvr(jweak dvrObj) { @@ -810,10 +837,17 @@ void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterE } } } - env->CallVoidMethod( - mFilterObj, - gFields.onFilterEventID, - array); + jobject filter(env->NewLocalRef(mFilterObj)); + if (!env->IsSameObject(filter, nullptr)) { + env->CallVoidMethod( + filter, + gFields.onFilterEventID, + array); + } else { + ALOGE("FilterClientCallbackImpl::onFilterEvent_1_1:" + "Filter object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mFilterObj); + } } void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) { @@ -828,10 +862,17 @@ void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) { ALOGD("FilterClientCallbackImpl::onFilterStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mFilterObj, - gFields.onFilterStatusID, - (jint)status); + jobject filter(env->NewLocalRef(mFilterObj)); + if (!env->IsSameObject(filter, nullptr)) { + env->CallVoidMethod( + filter, + gFields.onFilterStatusID, + (jint)status); + } else { + ALOGE("FilterClientCallbackImpl::onFilterStatus:" + "Filter object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mFilterObj); + } } void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) { @@ -841,6 +882,15 @@ void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filte mFilterClient = filterClient; } +FilterClientCallbackImpl::~FilterClientCallbackImpl() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (mFilterObj != NULL) { + env->DeleteWeakGlobalRef(mFilterObj); + mFilterObj = NULL; + } + mFilterClient = NULL; +} + /////////////// FrontendClientCallbackImpl /////////////////////// FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject(tunerObj) {} @@ -848,10 +898,17 @@ FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) { ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mObject, - gFields.onFrontendEventID, - (jint)frontendEventType); + jobject frontend(env->NewLocalRef(mObject)); + if (!env->IsSameObject(frontend, nullptr)) { + env->CallVoidMethod( + frontend, + gFields.onFrontendEventID, + (jint)frontendEventType); + } else { + ALOGE("FrontendClientCallbackImpl::onEvent:" + "Frontend object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mObject); + } } void FrontendClientCallbackImpl::onScanMessage( @@ -859,11 +916,18 @@ void FrontendClientCallbackImpl::onScanMessage( ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type); JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); + jobject frontend(env->NewLocalRef(mObject)); + if (env->IsSameObject(frontend, nullptr)) { + ALOGE("FrontendClientCallbackImpl::onScanMessage:" + "Frontend object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mObject); + return; + } switch(type) { case FrontendScanMessageType::LOCKED: { if (message.isLocked()) { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onLocked", "()V")); } break; @@ -871,14 +935,14 @@ void FrontendClientCallbackImpl::onScanMessage( case FrontendScanMessageType::END: { if (message.isEnd()) { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onScanStopped", "()V")); } break; } case FrontendScanMessageType::PROGRESS_PERCENT: { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onProgress", "(I)V"), (jint) message.progressPercent()); break; @@ -889,7 +953,7 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetIntArrayRegion(freqs, 0, v.size(), reinterpret_cast<jint*>(&v[0])); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onFrequenciesReport", "([I)V"), freqs); break; @@ -900,21 +964,21 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast<jint*>(&v[0])); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onSymbolRates", "([I)V"), symbolRates); break; } case FrontendScanMessageType::HIERARCHY: { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onHierarchy", "(I)V"), (jint) message.hierarchy()); break; } case FrontendScanMessageType::ANALOG_TYPE: { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onSignalType", "(I)V"), (jint) message.analogType()); break; @@ -926,7 +990,7 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetIntArrayRegion(plpIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onPlpIds", "([I)V"), plpIds); break; @@ -938,7 +1002,7 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetIntArrayRegion(groupIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onGroupIds", "([I)V"), groupIds); break; @@ -950,7 +1014,7 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetIntArrayRegion(streamIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onInputStreamIds", "([I)V"), streamIds); break; @@ -961,21 +1025,21 @@ void FrontendClientCallbackImpl::onScanMessage( if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sStd) { standard = (jint) std.sStd(); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onDvbsStandard", "(I)V"), standard); } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::tStd) { standard = (jint) std.tStd(); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onDvbtStandard", "(I)V"), standard); } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sifStd) { standard = (jint) std.sifStd(); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"), standard); } @@ -996,7 +1060,7 @@ void FrontendClientCallbackImpl::onScanMessage( env->SetObjectArrayElement(array, i, obj); } env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onAtsc3PlpInfos", "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"), array); @@ -1010,6 +1074,13 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1 ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type); JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); + jobject frontend(env->NewLocalRef(mObject)); + if (env->IsSameObject(frontend, nullptr)) { + ALOGE("FrontendClientCallbackImpl::onScanMessageExt1_1:" + "Frontend object has been freed. Ignoring callback."); + env->DeleteWeakGlobalRef(mObject); + return; + } switch(type) { case FrontendScanMessageTypeExt1_1::MODULATION: { jint modulation = -1; @@ -1056,7 +1127,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1 } if (modulation > 0) { env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onModulationReported", "(I)V"), modulation); } @@ -1065,7 +1136,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1 case FrontendScanMessageTypeExt1_1::HIGH_PRIORITY: { bool isHighPriority = message.isHighPriority(); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onPriorityReported", "(B)V"), isHighPriority); break; @@ -1073,7 +1144,7 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1 case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: { jint dvbcAnnex = (jint) message.annex(); env->CallVoidMethod( - mObject, + frontend, env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"), dvbcAnnex); break; @@ -1083,6 +1154,14 @@ void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1 } } +FrontendClientCallbackImpl::~FrontendClientCallbackImpl() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (mObject != NULL) { + env->DeleteWeakGlobalRef(mObject); + mObject = NULL; + } +} + /////////////// Tuner /////////////////////// sp<TunerClient> JTuner::mTunerClient; @@ -1158,15 +1237,23 @@ jobject JTuner::openFrontendByHandle(int feHandle) { if (mDemuxClient != NULL) { mDemuxClient->setFrontendDataSource(mFeClient); } - sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject); - mFeClient->setCallback(feClientCb); JNIEnv *env = AndroidRuntime::getJNIEnv(); + jobject tuner(env->NewLocalRef(mObject)); + if (env->IsSameObject(tuner, nullptr)) { + ALOGE("openFrontendByHandle" + "Tuner object has been freed. Failed to open frontend."); + env->DeleteWeakGlobalRef(mObject); + return NULL; + } + + sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject); + mFeClient->setCallback(feClientCb); // TODO: add more fields to frontend return env->NewObject( env->FindClass("android/media/tv/tuner/Tuner$Frontend"), gFields.frontendInitID, - mObject, + tuner, (jint) mFeId); } @@ -1714,16 +1801,14 @@ jobject JTuner::openDvr(DvrType type, jlong bufferSize) { dvrObj = env->NewObject( env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"), - gFields.dvrRecorderInitID, - mObject); + gFields.dvrRecorderInitID); dvrClient->incStrong(dvrObj); env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrClient.get()); } else { dvrObj = env->NewObject( env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"), - gFields.dvrPlaybackInitID, - mObject); + gFields.dvrPlaybackInitID); dvrClient->incStrong(dvrObj); env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrClient.get()); } diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 0e30b18eb2d4..fafef4221541 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -118,6 +118,7 @@ struct MediaEvent : public RefBase { }; struct FilterClientCallbackImpl : public FilterClientCallback { + ~FilterClientCallbackImpl(); virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent, const DemuxFilterEventExt& filterEventExt); virtual void onFilterEvent(const DemuxFilterEvent& filterEvent); @@ -155,7 +156,7 @@ private: struct FrontendClientCallbackImpl : public FrontendClientCallback { FrontendClientCallbackImpl(jweak tunerObj); - + ~FrontendClientCallbackImpl(); virtual void onEvent(FrontendEventType frontendEventType); virtual void onScanMessage( FrontendScanMessageType type, const FrontendScanMessage& message); diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 4efdcaccf7a1..ffed4747d3ea 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -32,6 +32,7 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> +#include "core_jni_helpers.h" #include <jni.h> #include <media/stagefright/NuMediaExtractor.h> #include <nativehelper/JNIHelp.h> @@ -48,6 +49,7 @@ using namespace android; // ---------------------------------------------------------------------------- +// MtpDatabase methods static jmethodID method_beginSendObject; static jmethodID method_endSendObject; static jmethodID method_rescanFile; @@ -75,6 +77,7 @@ static jmethodID method_endCopyObject; static jmethodID method_getObjectReferences; static jmethodID method_setObjectReferences; +// MtpDatabase fields. static jfieldID field_context; // MtpPropertyList methods @@ -86,6 +89,59 @@ static jmethodID method_getDataTypes; static jmethodID method_getLongValues; static jmethodID method_getStringValues; +// Initializer for the jfieldIDs and jmethodIDs above. This method must be invoked +// before using these static fields and methods for JNI accesses. +static void initializeJavaIDs(JNIEnv* env) { + static std::once_flag sJniInitialized; + +#define GET_METHOD_ID(name, jclass, signature) \ + method_##name = GetMethodIDOrDie(env, jclass, #name, signature); + + std::call_once(sJniInitialized, [](JNIEnv* env) { + const jclass mdb_class = FindClassOrDie(env, "android/mtp/MtpDatabase"); + GET_METHOD_ID(beginSendObject, mdb_class, "(Ljava/lang/String;III)I"); + GET_METHOD_ID(endSendObject, mdb_class, "(IZ)V"); + GET_METHOD_ID(rescanFile, mdb_class, "(Ljava/lang/String;II)V"); + GET_METHOD_ID(getObjectList, mdb_class, "(III)[I"); + GET_METHOD_ID(getNumObjects, mdb_class, "(III)I"); + GET_METHOD_ID(getSupportedPlaybackFormats, mdb_class, "()[I"); + GET_METHOD_ID(getSupportedCaptureFormats, mdb_class, "()[I"); + GET_METHOD_ID(getSupportedObjectProperties, mdb_class, "(I)[I"); + GET_METHOD_ID(getSupportedDeviceProperties, mdb_class, "()[I"); + GET_METHOD_ID(setObjectProperty, mdb_class, "(IIJLjava/lang/String;)I"); + GET_METHOD_ID(getDeviceProperty, mdb_class, "(I[J[C)I"); + GET_METHOD_ID(setDeviceProperty, mdb_class, "(IJLjava/lang/String;)I"); + GET_METHOD_ID(getObjectPropertyList, mdb_class, "(IIIII)Landroid/mtp/MtpPropertyList;"); + GET_METHOD_ID(getObjectInfo, mdb_class, "(I[I[C[J)Z"); + GET_METHOD_ID(getObjectFilePath, mdb_class, "(I[C[J)I"); + GET_METHOD_ID(openFilePath, mdb_class, "(Ljava/lang/String;Z)I"); + GET_METHOD_ID(getThumbnailInfo, mdb_class, "(I[J)Z"); + GET_METHOD_ID(getThumbnailData, mdb_class, "(I)[B"); + GET_METHOD_ID(beginDeleteObject, mdb_class, "(I)I"); + GET_METHOD_ID(endDeleteObject, mdb_class, "(IZ)V"); + GET_METHOD_ID(beginMoveObject, mdb_class, "(III)I"); + GET_METHOD_ID(endMoveObject, mdb_class, "(IIIIIZ)V"); + GET_METHOD_ID(beginCopyObject, mdb_class, "(III)I"); + GET_METHOD_ID(endCopyObject, mdb_class, "(IZ)V"); + GET_METHOD_ID(getObjectReferences, mdb_class, "(I)[I"); + GET_METHOD_ID(setObjectReferences, mdb_class, "(I[I)I"); + field_context = GetFieldIDOrDie(env, mdb_class, "mNativeContext", "J"); + + const jclass mpl_class = FindClassOrDie(env, "android/mtp/MtpPropertyList"); + GET_METHOD_ID(getCode, mpl_class, "()I"); + GET_METHOD_ID(getCount, mpl_class, "()I"); + GET_METHOD_ID(getObjectHandles, mpl_class, "()[I"); + GET_METHOD_ID(getPropertyCodes, mpl_class, "()[I"); + GET_METHOD_ID(getDataTypes, mpl_class, "()[I"); + GET_METHOD_ID(getLongValues, mpl_class, "()[J"); + GET_METHOD_ID(getStringValues, mpl_class, "()[Ljava/lang/String;"); + + return 0; + }, env); + +#undef GET_METHOD_ID +} + IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) { return (IMtpDatabase *)env->GetLongField(database, field_context); @@ -1280,6 +1336,7 @@ MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { static void android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz) { + initializeJavaIDs(env); MtpDatabase* database = new MtpDatabase(env, thiz); env->SetLongField(thiz, field_context, (jlong)database); checkAndClearExceptionFromCallback(env, __FUNCTION__); @@ -1314,69 +1371,9 @@ static const JNINativeMethod gMtpPropertyGroupMethods[] = { {"format_date_time", "(J)Ljava/lang/String;", (void *)android_mtp_MtpPropertyGroup_format_date_time}, }; - -#define GET_METHOD_ID(name, jclass, signature) \ - method_##name = env->GetMethodID(jclass, #name, signature); \ - if (method_##name == NULL) { \ - ALOGE("Can't find " #name); \ - return -1; \ - } \ - + \ int register_android_mtp_MtpDatabase(JNIEnv *env) { - jclass clazz; - - clazz = env->FindClass("android/mtp/MtpDatabase"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpDatabase"); - return -1; - } - GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I"); - GET_METHOD_ID(endSendObject, clazz, "(IZ)V"); - GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V"); - GET_METHOD_ID(getObjectList, clazz, "(III)[I"); - GET_METHOD_ID(getNumObjects, clazz, "(III)I"); - GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I"); - GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I"); - GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I"); - GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I"); - GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I"); - GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I"); - GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I"); - GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;"); - GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z"); - GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I"); - GET_METHOD_ID(openFilePath, clazz, "(Ljava/lang/String;Z)I"); - GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z"); - GET_METHOD_ID(getThumbnailData, clazz, "(I)[B"); - GET_METHOD_ID(beginDeleteObject, clazz, "(I)I"); - GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V"); - GET_METHOD_ID(beginMoveObject, clazz, "(III)I"); - GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V"); - GET_METHOD_ID(beginCopyObject, clazz, "(III)I"); - GET_METHOD_ID(endCopyObject, clazz, "(IZ)V"); - GET_METHOD_ID(getObjectReferences, clazz, "(I)[I"); - GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I"); - - field_context = env->GetFieldID(clazz, "mNativeContext", "J"); - if (field_context == NULL) { - ALOGE("Can't find MtpDatabase.mNativeContext"); - return -1; - } - - clazz = env->FindClass("android/mtp/MtpPropertyList"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpPropertyList"); - return -1; - } - GET_METHOD_ID(getCode, clazz, "()I"); - GET_METHOD_ID(getCount, clazz, "()I"); - GET_METHOD_ID(getObjectHandles, clazz, "()[I"); - GET_METHOD_ID(getPropertyCodes, clazz, "()[I"); - GET_METHOD_ID(getDataTypes, clazz, "()[I"); - GET_METHOD_ID(getLongValues, clazz, "()[J"); - GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;"); - if (AndroidRuntime::registerNativeMethods(env, "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods))) return -1; diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 060eaf9ccad4..3d2b00fec26c 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -34,6 +34,7 @@ #include "android_runtime/AndroidRuntime.h" #include "android_runtime/Log.h" +#include "core_jni_helpers.h" #include "nativehelper/ScopedLocalRef.h" #include "private/android_filesystem_config.h" @@ -107,6 +108,95 @@ static jfieldID field_event_parameter1; static jfieldID field_event_parameter2; static jfieldID field_event_parameter3; +// Initializer for the jclasses, jfieldIDs and jmethodIDs declared above. This method must be +// invoked before using these static fields for JNI accesses. +static void initializeJavaIDs(JNIEnv* env) { + static std::once_flag sJniInitialized; + + std::call_once(sJniInitialized, [](JNIEnv* env) { + clazz_deviceInfo = + (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpDeviceInfo")); + constructor_deviceInfo = GetMethodIDOrDie(env, clazz_deviceInfo, "<init>", "()V"); + field_deviceInfo_manufacturer = + GetFieldIDOrDie(env, clazz_deviceInfo, "mManufacturer", "Ljava/lang/String;"); + field_deviceInfo_model = + GetFieldIDOrDie(env, clazz_deviceInfo, "mModel", "Ljava/lang/String;"); + field_deviceInfo_version = + GetFieldIDOrDie(env, clazz_deviceInfo, "mVersion", "Ljava/lang/String;"); + field_deviceInfo_serialNumber = + GetFieldIDOrDie(env, clazz_deviceInfo, "mSerialNumber", "Ljava/lang/String;"); + field_deviceInfo_operationsSupported = + GetFieldIDOrDie(env, clazz_deviceInfo, "mOperationsSupported", "[I"); + field_deviceInfo_eventsSupported = + GetFieldIDOrDie(env, clazz_deviceInfo, "mEventsSupported", "[I"); + + clazz_storageInfo = + (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpStorageInfo")); + constructor_storageInfo = GetMethodIDOrDie(env, clazz_storageInfo, "<init>", "()V"); + field_storageInfo_storageId = GetFieldIDOrDie(env, clazz_storageInfo, "mStorageId", "I"); + field_storageInfo_maxCapacity = + GetFieldIDOrDie(env, clazz_storageInfo, "mMaxCapacity", "J"); + field_storageInfo_freeSpace = + GetFieldIDOrDie(env, clazz_storageInfo, "mFreeSpace", "J"); + field_storageInfo_description = + GetFieldIDOrDie(env, clazz_storageInfo, "mDescription", "Ljava/lang/String;"); + field_storageInfo_volumeIdentifier = + GetFieldIDOrDie(env, clazz_storageInfo, "mVolumeIdentifier", "Ljava/lang/String;"); + + clazz_objectInfo = + (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpObjectInfo")); + constructor_objectInfo = GetMethodIDOrDie(env, clazz_objectInfo, "<init>", "()V"); + field_objectInfo_handle = GetFieldIDOrDie(env, clazz_objectInfo, "mHandle", "I"); + field_objectInfo_storageId = GetFieldIDOrDie(env, clazz_objectInfo, "mStorageId", "I"); + field_objectInfo_format = GetFieldIDOrDie(env, clazz_objectInfo, "mFormat", "I"); + field_objectInfo_protectionStatus = + GetFieldIDOrDie(env, clazz_objectInfo, "mProtectionStatus", "I"); + field_objectInfo_compressedSize = + GetFieldIDOrDie(env, clazz_objectInfo, "mCompressedSize", "I"); + field_objectInfo_thumbFormat = GetFieldIDOrDie(env, clazz_objectInfo, "mThumbFormat", "I"); + field_objectInfo_thumbCompressedSize = + GetFieldIDOrDie(env, clazz_objectInfo, "mThumbCompressedSize", "I"); + field_objectInfo_thumbPixWidth = + GetFieldIDOrDie(env, clazz_objectInfo, "mThumbPixWidth", "I"); + field_objectInfo_thumbPixHeight = + GetFieldIDOrDie(env, clazz_objectInfo, "mThumbPixHeight", "I"); + field_objectInfo_imagePixWidth = + GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixWidth", "I"); + field_objectInfo_imagePixHeight = + GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixHeight", "I"); + field_objectInfo_imagePixDepth = + GetFieldIDOrDie(env, clazz_objectInfo, "mImagePixDepth", "I"); + field_objectInfo_parent = GetFieldIDOrDie(env, clazz_objectInfo, "mParent", "I"); + field_objectInfo_associationType = + GetFieldIDOrDie(env, clazz_objectInfo, "mAssociationType", "I"); + field_objectInfo_associationDesc = + GetFieldIDOrDie(env, clazz_objectInfo, "mAssociationDesc", "I"); + field_objectInfo_sequenceNumber = + GetFieldIDOrDie(env, clazz_objectInfo, "mSequenceNumber", "I"); + field_objectInfo_name = + GetFieldIDOrDie(env, clazz_objectInfo, "mName", "Ljava/lang/String;"); + field_objectInfo_dateCreated = GetFieldIDOrDie(env, clazz_objectInfo, "mDateCreated", "J"); + field_objectInfo_dateModified = + GetFieldIDOrDie(env, clazz_objectInfo, "mDateModified", "J"); + field_objectInfo_keywords = + GetFieldIDOrDie(env, clazz_objectInfo, "mKeywords", "Ljava/lang/String;"); + + clazz_event = (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpEvent")); + constructor_event = GetMethodIDOrDie(env, clazz_event, "<init>", "()V"); + field_event_eventCode = GetFieldIDOrDie(env, clazz_event, "mEventCode", "I"); + field_event_parameter1 = GetFieldIDOrDie(env, clazz_event, "mParameter1", "I"); + field_event_parameter2 = GetFieldIDOrDie(env, clazz_event, "mParameter2", "I"); + field_event_parameter3 = GetFieldIDOrDie(env, clazz_event, "mParameter3", "I"); + + const jclass clazz = FindClassOrDie(env, "android/mtp/MtpDevice"); + field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J"); + + clazz_io_exception = (jclass)env->NewGlobalRef(FindClassOrDie(env, "java/io/IOException")); + clazz_operation_canceled_exception = + (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/os/OperationCanceledException")); + }, env); +} + class JavaArrayWriter { public: JavaArrayWriter(JNIEnv* env, jbyteArray array) : @@ -132,6 +222,11 @@ private: MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice) { + // get_device_from_object() is called by the majority of JNI methods in this file. Call + // `initializeJavaIDs()` here to ensure JNI methodID's, fieldIDs and classes are initialized + // before use. + initializeJavaIDs(env); + return (MtpDevice*)env->GetLongField(javaDevice, field_context); } @@ -200,6 +295,8 @@ android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint f MtpDevice* device = MtpDevice::open(deviceNameStr, fd); env->ReleaseStringUTFChars(deviceName, deviceNameStr); + // The jfieldID `field_context` needs to be initialized before use below. + initializeJavaIDs(env); if (device) env->SetLongField(thiz, field_context, (jlong)device); return (jboolean)(device != NULL); @@ -781,256 +878,7 @@ static const JNINativeMethod gMethods[] = { int register_android_mtp_MtpDevice(JNIEnv *env) { - jclass clazz; - ALOGD("register_android_mtp_MtpDevice\n"); - - clazz = env->FindClass("android/mtp/MtpDeviceInfo"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpDeviceInfo"); - return -1; - } - constructor_deviceInfo = env->GetMethodID(clazz, "<init>", "()V"); - if (constructor_deviceInfo == NULL) { - ALOGE("Can't find android/mtp/MtpDeviceInfo constructor"); - return -1; - } - field_deviceInfo_manufacturer = env->GetFieldID(clazz, "mManufacturer", "Ljava/lang/String;"); - if (field_deviceInfo_manufacturer == NULL) { - ALOGE("Can't find MtpDeviceInfo.mManufacturer"); - return -1; - } - field_deviceInfo_model = env->GetFieldID(clazz, "mModel", "Ljava/lang/String;"); - if (field_deviceInfo_model == NULL) { - ALOGE("Can't find MtpDeviceInfo.mModel"); - return -1; - } - field_deviceInfo_version = env->GetFieldID(clazz, "mVersion", "Ljava/lang/String;"); - if (field_deviceInfo_version == NULL) { - ALOGE("Can't find MtpDeviceInfo.mVersion"); - return -1; - } - field_deviceInfo_serialNumber = env->GetFieldID(clazz, "mSerialNumber", "Ljava/lang/String;"); - if (field_deviceInfo_serialNumber == NULL) { - ALOGE("Can't find MtpDeviceInfo.mSerialNumber"); - return -1; - } - field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I"); - if (field_deviceInfo_operationsSupported == NULL) { - ALOGE("Can't find MtpDeviceInfo.mOperationsSupported"); - return -1; - } - field_deviceInfo_eventsSupported = env->GetFieldID(clazz, "mEventsSupported", "[I"); - if (field_deviceInfo_eventsSupported == NULL) { - ALOGE("Can't find MtpDeviceInfo.mEventsSupported"); - return -1; - } - clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz); - - clazz = env->FindClass("android/mtp/MtpStorageInfo"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpStorageInfo"); - return -1; - } - constructor_storageInfo = env->GetMethodID(clazz, "<init>", "()V"); - if (constructor_storageInfo == NULL) { - ALOGE("Can't find android/mtp/MtpStorageInfo constructor"); - return -1; - } - field_storageInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I"); - if (field_storageInfo_storageId == NULL) { - ALOGE("Can't find MtpStorageInfo.mStorageId"); - return -1; - } - field_storageInfo_maxCapacity = env->GetFieldID(clazz, "mMaxCapacity", "J"); - if (field_storageInfo_maxCapacity == NULL) { - ALOGE("Can't find MtpStorageInfo.mMaxCapacity"); - return -1; - } - field_storageInfo_freeSpace = env->GetFieldID(clazz, "mFreeSpace", "J"); - if (field_storageInfo_freeSpace == NULL) { - ALOGE("Can't find MtpStorageInfo.mFreeSpace"); - return -1; - } - field_storageInfo_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); - if (field_storageInfo_description == NULL) { - ALOGE("Can't find MtpStorageInfo.mDescription"); - return -1; - } - field_storageInfo_volumeIdentifier = env->GetFieldID(clazz, "mVolumeIdentifier", "Ljava/lang/String;"); - if (field_storageInfo_volumeIdentifier == NULL) { - ALOGE("Can't find MtpStorageInfo.mVolumeIdentifier"); - return -1; - } - clazz_storageInfo = (jclass)env->NewGlobalRef(clazz); - - clazz = env->FindClass("android/mtp/MtpObjectInfo"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpObjectInfo"); - return -1; - } - constructor_objectInfo = env->GetMethodID(clazz, "<init>", "()V"); - if (constructor_objectInfo == NULL) { - ALOGE("Can't find android/mtp/MtpObjectInfo constructor"); - return -1; - } - field_objectInfo_handle = env->GetFieldID(clazz, "mHandle", "I"); - if (field_objectInfo_handle == NULL) { - ALOGE("Can't find MtpObjectInfo.mHandle"); - return -1; - } - field_objectInfo_storageId = env->GetFieldID(clazz, "mStorageId", "I"); - if (field_objectInfo_storageId == NULL) { - ALOGE("Can't find MtpObjectInfo.mStorageId"); - return -1; - } - field_objectInfo_format = env->GetFieldID(clazz, "mFormat", "I"); - if (field_objectInfo_format == NULL) { - ALOGE("Can't find MtpObjectInfo.mFormat"); - return -1; - } - field_objectInfo_protectionStatus = env->GetFieldID(clazz, "mProtectionStatus", "I"); - if (field_objectInfo_protectionStatus == NULL) { - ALOGE("Can't find MtpObjectInfo.mProtectionStatus"); - return -1; - } - field_objectInfo_compressedSize = env->GetFieldID(clazz, "mCompressedSize", "I"); - if (field_objectInfo_compressedSize == NULL) { - ALOGE("Can't find MtpObjectInfo.mCompressedSize"); - return -1; - } - field_objectInfo_thumbFormat = env->GetFieldID(clazz, "mThumbFormat", "I"); - if (field_objectInfo_thumbFormat == NULL) { - ALOGE("Can't find MtpObjectInfo.mThumbFormat"); - return -1; - } - field_objectInfo_thumbCompressedSize = env->GetFieldID(clazz, "mThumbCompressedSize", "I"); - if (field_objectInfo_thumbCompressedSize == NULL) { - ALOGE("Can't find MtpObjectInfo.mThumbCompressedSize"); - return -1; - } - field_objectInfo_thumbPixWidth = env->GetFieldID(clazz, "mThumbPixWidth", "I"); - if (field_objectInfo_thumbPixWidth == NULL) { - ALOGE("Can't find MtpObjectInfo.mThumbPixWidth"); - return -1; - } - field_objectInfo_thumbPixHeight = env->GetFieldID(clazz, "mThumbPixHeight", "I"); - if (field_objectInfo_thumbPixHeight == NULL) { - ALOGE("Can't find MtpObjectInfo.mThumbPixHeight"); - return -1; - } - field_objectInfo_imagePixWidth = env->GetFieldID(clazz, "mImagePixWidth", "I"); - if (field_objectInfo_imagePixWidth == NULL) { - ALOGE("Can't find MtpObjectInfo.mImagePixWidth"); - return -1; - } - field_objectInfo_imagePixHeight = env->GetFieldID(clazz, "mImagePixHeight", "I"); - if (field_objectInfo_imagePixHeight == NULL) { - ALOGE("Can't find MtpObjectInfo.mImagePixHeight"); - return -1; - } - field_objectInfo_imagePixDepth = env->GetFieldID(clazz, "mImagePixDepth", "I"); - if (field_objectInfo_imagePixDepth == NULL) { - ALOGE("Can't find MtpObjectInfo.mImagePixDepth"); - return -1; - } - field_objectInfo_parent = env->GetFieldID(clazz, "mParent", "I"); - if (field_objectInfo_parent == NULL) { - ALOGE("Can't find MtpObjectInfo.mParent"); - return -1; - } - field_objectInfo_associationType = env->GetFieldID(clazz, "mAssociationType", "I"); - if (field_objectInfo_associationType == NULL) { - ALOGE("Can't find MtpObjectInfo.mAssociationType"); - return -1; - } - field_objectInfo_associationDesc = env->GetFieldID(clazz, "mAssociationDesc", "I"); - if (field_objectInfo_associationDesc == NULL) { - ALOGE("Can't find MtpObjectInfo.mAssociationDesc"); - return -1; - } - field_objectInfo_sequenceNumber = env->GetFieldID(clazz, "mSequenceNumber", "I"); - if (field_objectInfo_sequenceNumber == NULL) { - ALOGE("Can't find MtpObjectInfo.mSequenceNumber"); - return -1; - } - field_objectInfo_name = env->GetFieldID(clazz, "mName", "Ljava/lang/String;"); - if (field_objectInfo_name == NULL) { - ALOGE("Can't find MtpObjectInfo.mName"); - return -1; - } - field_objectInfo_dateCreated = env->GetFieldID(clazz, "mDateCreated", "J"); - if (field_objectInfo_dateCreated == NULL) { - ALOGE("Can't find MtpObjectInfo.mDateCreated"); - return -1; - } - field_objectInfo_dateModified = env->GetFieldID(clazz, "mDateModified", "J"); - if (field_objectInfo_dateModified == NULL) { - ALOGE("Can't find MtpObjectInfo.mDateModified"); - return -1; - } - field_objectInfo_keywords = env->GetFieldID(clazz, "mKeywords", "Ljava/lang/String;"); - if (field_objectInfo_keywords == NULL) { - ALOGE("Can't find MtpObjectInfo.mKeywords"); - return -1; - } - clazz_objectInfo = (jclass)env->NewGlobalRef(clazz); - - clazz = env->FindClass("android/mtp/MtpEvent"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpEvent"); - return -1; - } - constructor_event = env->GetMethodID(clazz, "<init>", "()V"); - if (constructor_event == NULL) { - ALOGE("Can't find android/mtp/MtpEvent constructor"); - return -1; - } - field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I"); - if (field_event_eventCode == NULL) { - ALOGE("Can't find MtpObjectInfo.mEventCode"); - return -1; - } - field_event_parameter1 = env->GetFieldID(clazz, "mParameter1", "I"); - if (field_event_parameter1 == NULL) { - ALOGE("Can't find MtpObjectInfo.mParameter1"); - return -1; - } - field_event_parameter2 = env->GetFieldID(clazz, "mParameter2", "I"); - if (field_event_parameter2 == NULL) { - ALOGE("Can't find MtpObjectInfo.mParameter2"); - return -1; - } - field_event_parameter3 = env->GetFieldID(clazz, "mParameter3", "I"); - if (field_event_parameter3 == NULL) { - ALOGE("Can't find MtpObjectInfo.mParameter3"); - return -1; - } - clazz_event = (jclass)env->NewGlobalRef(clazz); - - clazz = env->FindClass("android/mtp/MtpDevice"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpDevice"); - return -1; - } - field_context = env->GetFieldID(clazz, "mNativeContext", "J"); - if (field_context == NULL) { - ALOGE("Can't find MtpDevice.mNativeContext"); - return -1; - } - clazz = env->FindClass("java/io/IOException"); - if (clazz == NULL) { - ALOGE("Can't find java.io.IOException"); - return -1; - } - clazz_io_exception = (jclass)env->NewGlobalRef(clazz); - clazz = env->FindClass("android/os/OperationCanceledException"); - if (clazz == NULL) { - ALOGE("Can't find android.os.OperationCanceledException"); - return -1; - } - clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz); - return AndroidRuntime::registerNativeMethods(env, "android/mtp/MtpDevice", gMethods, NELEM(gMethods)); } diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index 8a1ae9252ca3..b4844f79b540 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -24,6 +24,7 @@ #include <fcntl.h> #include <utils/threads.h> +#include "core_jni_helpers.h" #include "jni.h" #include <nativehelper/JNIPlatformHelp.h> #include "android_runtime/AndroidRuntime.h" @@ -34,6 +35,8 @@ using namespace android; +static Mutex sMutex; + // MtpServer fields static jfieldID field_MtpServer_nativeContext; @@ -44,7 +47,25 @@ static jfieldID field_MtpStorage_description; static jfieldID field_MtpStorage_removable; static jfieldID field_MtpStorage_maxFileSize; -static Mutex sMutex; +// Initializer for the jfieldIDs above. This method must be invoked before accessing MtpServer and +// MtpStorage fields. +static void initializeJavaIDs(JNIEnv* env) { + static std::once_flag sJniInitialized; + + std::call_once(sJniInitialized, [](JNIEnv *env) { + const jclass storage_clazz = FindClassOrDie(env, "android/mtp/MtpStorage"); + field_MtpStorage_storageId = GetFieldIDOrDie(env, storage_clazz, "mStorageId", "I"); + field_MtpStorage_path = + GetFieldIDOrDie(env, storage_clazz, "mPath", "Ljava/lang/String;"); + field_MtpStorage_description = + GetFieldIDOrDie(env, storage_clazz, "mDescription", "Ljava/lang/String;"); + field_MtpStorage_removable = GetFieldIDOrDie(env, storage_clazz, "mRemovable", "Z"); + field_MtpStorage_maxFileSize = GetFieldIDOrDie(env, storage_clazz, "mMaxFileSize", "J"); + + const jclass server_clazz = FindClassOrDie(env, "android/mtp/MtpServer"); + field_MtpServer_nativeContext = GetFieldIDOrDie(env, server_clazz, "mNativeContext", "J"); + }, env); +} // ---------------------------------------------------------------------------- @@ -52,6 +73,7 @@ static Mutex sMutex; extern IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) { + initializeJavaIDs(env); return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext); } @@ -60,6 +82,8 @@ android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, job jboolean usePtp, jstring deviceInfoManufacturer, jstring deviceInfoModel, jstring deviceInfoDeviceVersion, jstring deviceInfoSerialNumber) { + initializeJavaIDs(env); + const char *deviceInfoManufacturerStr = env->GetStringUTFChars(deviceInfoManufacturer, NULL); const char *deviceInfoModelStr = env->GetStringUTFChars(deviceInfoModel, NULL); const char *deviceInfoDeviceVersionStr = env->GetStringUTFChars(deviceInfoDeviceVersion, NULL); @@ -224,50 +248,6 @@ static const JNINativeMethod gMethods[] = { int register_android_mtp_MtpServer(JNIEnv *env) { - jclass clazz; - - clazz = env->FindClass("android/mtp/MtpStorage"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpStorage"); - return -1; - } - field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); - if (field_MtpStorage_storageId == NULL) { - ALOGE("Can't find MtpStorage.mStorageId"); - return -1; - } - field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); - if (field_MtpStorage_path == NULL) { - ALOGE("Can't find MtpStorage.mPath"); - return -1; - } - field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); - if (field_MtpStorage_description == NULL) { - ALOGE("Can't find MtpStorage.mDescription"); - return -1; - } - field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); - if (field_MtpStorage_removable == NULL) { - ALOGE("Can't find MtpStorage.mRemovable"); - return -1; - } - field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); - if (field_MtpStorage_maxFileSize == NULL) { - ALOGE("Can't find MtpStorage.mMaxFileSize"); - return -1; - } - - clazz = env->FindClass("android/mtp/MtpServer"); - if (clazz == NULL) { - ALOGE("Can't find android/mtp/MtpServer"); - return -1; - } - field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); - if (field_MtpServer_nativeContext == NULL) { - ALOGE("Can't find MtpServer.mNativeContext"); - return -1; - } - return AndroidRuntime::registerNativeMethods(env, "android/mtp/MtpServer", gMethods, NELEM(gMethods)); } diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index 7b498e027d1c..b3406cd89046 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -45,26 +45,30 @@ tidy_errors = [ "modernize-return-braced-init-list", "modernize-shrink-to-fit", "modernize-unary-static-assert", - "modernize-use-auto", // debatable - auto can obscure type + // "modernize-use-auto", // found in StreamManager.h, debatable - auto can obscure type "modernize-use-bool-literals", "modernize-use-default-member-init", "modernize-use-emplace", "modernize-use-equals-default", "modernize-use-equals-delete", - "modernize-use-nodiscard", + // "modernize-use-nodiscard", // found in SteamManager.h "modernize-use-noexcept", "modernize-use-nullptr", "modernize-use-override", //"modernize-use-trailing-return-type", // not necessarily more readable "modernize-use-transparent-functors", "modernize-use-uncaught-exceptions", - "modernize-use-using", + //"modernize-use-using", // found in SoundManager.h "performance-*", // Remove some pedantic stylistic requirements. "-google-readability-casting", // C++ casts not always necessary and may be verbose "-google-readability-todo", // do not require TODO(info) "-google-build-using-namespace", // Reenable and fix later. + + "-google-explicit-constructor", // found in StreamManager.h + "-misc-non-private-member-variables-in-classes", // found in SoundManager.h + "-performance-unnecessary-value-param", // found in StreamManager.h ] cc_defaults { @@ -96,8 +100,7 @@ cc_defaults { tidy_checks: tidy_errors, tidy_checks_as_errors: tidy_errors, tidy_flags: [ - "-format-style='file'", - "--header-filter='frameworks/base/media/jni/soundpool'", + "-format-style=file", ], } diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java index f4b46e9f11ed..eafda4d2d694 100644 --- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java +++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java @@ -44,7 +44,7 @@ public final class CaptivePortalData implements Parcelable { private final boolean mCaptive; private final String mVenueFriendlyName; private final int mVenueInfoUrlSource; - private final int mTermsAndConditionsSource; + private final int mUserPortalUrlSource; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -65,7 +65,7 @@ public final class CaptivePortalData implements Parcelable { private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive, - String venueFriendlyName, int venueInfoUrlSource, int termsAndConditionsSource) { + String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) { mRefreshTimeMillis = refreshTimeMillis; mUserPortalUrl = userPortalUrl; mVenueInfoUrl = venueInfoUrl; @@ -75,7 +75,7 @@ public final class CaptivePortalData implements Parcelable { mCaptive = captive; mVenueFriendlyName = venueFriendlyName; mVenueInfoUrlSource = venueInfoUrlSource; - mTermsAndConditionsSource = termsAndConditionsSource; + mUserPortalUrlSource = userPortalUrlSource; } private CaptivePortalData(Parcel p) { @@ -100,7 +100,7 @@ public final class CaptivePortalData implements Parcelable { dest.writeBoolean(mCaptive); dest.writeString(mVenueFriendlyName); dest.writeInt(mVenueInfoUrlSource); - dest.writeInt(mTermsAndConditionsSource); + dest.writeInt(mUserPortalUrlSource); } /** @@ -130,7 +130,7 @@ public final class CaptivePortalData implements Parcelable { public Builder(@Nullable CaptivePortalData data) { if (data == null) return; setRefreshTime(data.mRefreshTimeMillis) - .setUserPortalUrl(data.mUserPortalUrl, data.mTermsAndConditionsSource) + .setUserPortalUrl(data.mUserPortalUrl, data.mUserPortalUrlSource) .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource) .setSessionExtendable(data.mIsSessionExtendable) .setBytesRemaining(data.mByteLimit) @@ -314,7 +314,7 @@ public final class CaptivePortalData implements Parcelable { * @return The source that the user portal URL was obtained from */ public @CaptivePortalDataSource int getUserPortalUrlSource() { - return mTermsAndConditionsSource; + return mUserPortalUrlSource; } /** @@ -342,7 +342,7 @@ public final class CaptivePortalData implements Parcelable { public int hashCode() { return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl, mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName, - mVenueInfoUrlSource, mTermsAndConditionsSource); + mVenueInfoUrlSource, mUserPortalUrlSource); } @Override @@ -358,7 +358,7 @@ public final class CaptivePortalData implements Parcelable { && mCaptive == other.mCaptive && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName) && mVenueInfoUrlSource == other.mVenueInfoUrlSource - && mTermsAndConditionsSource == other.mTermsAndConditionsSource; + && mUserPortalUrlSource == other.mUserPortalUrlSource; } @Override @@ -373,7 +373,7 @@ public final class CaptivePortalData implements Parcelable { + ", captive: " + mCaptive + ", venueFriendlyName: " + mVenueFriendlyName + ", venueInfoUrlSource: " + mVenueInfoUrlSource - + ", termsAndConditionsSource: " + mTermsAndConditionsSource + + ", userPortalUrlSource: " + mUserPortalUrlSource + "}"; } } diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 4ddae533bb80..e7ab0a1c7ac8 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -1067,58 +1067,6 @@ public class ConnectivityManager { } /** - * Calls VpnManager#isAlwaysOnVpnPackageSupportedForUser. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) { - return getVpnManager().isAlwaysOnVpnPackageSupportedForUser(userId, vpnPackage); - } - - /** - * Calls VpnManager#setAlwaysOnVpnPackageForUser. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) { - return getVpnManager().setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdownEnabled, - lockdownAllowlist); - } - - /** - * Calls VpnManager#getAlwaysOnVpnPackageForUser. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public String getAlwaysOnVpnPackageForUser(int userId) { - return getVpnManager().getAlwaysOnVpnPackageForUser(userId); - } - - /** - * Calls VpnManager#isVpnLockdownEnabled. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public boolean isVpnLockdownEnabled(int userId) { - return getVpnManager().isVpnLockdownEnabled(userId); - } - - /** - * Calls VpnManager#getVpnLockdownAllowlist. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public List<String> getVpnLockdownAllowlist(int userId) { - return getVpnManager().getVpnLockdownAllowlist(userId); - } - - /** * Adds or removes a requirement for given UID ranges to use the VPN. * * If set to {@code true}, informs the system that the UIDs in the specified ranges must not @@ -3153,16 +3101,6 @@ public class ConnectivityManager { } /** - * Calls VpnManager#updateLockdownVpn. - * @deprecated TODO: remove when callers have migrated to VpnManager. - * @hide - */ - @Deprecated - public boolean updateLockdownVpn() { - return getVpnManager().updateLockdownVpn(); - } - - /** * Set sign in error notification to visible or invisible * * @hide @@ -4523,8 +4461,6 @@ public class ConnectivityManager { try { mService.factoryReset(); mTetheringManager.stopAllTethering(); - // TODO: Migrate callers to VpnManager#factoryReset. - getVpnManager().factoryReset(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4818,15 +4754,6 @@ public class ConnectivityManager { return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder)); } - /** - * Temporary hack to shim calls from ConnectivityManager to VpnManager. We cannot store a - * private final mVpnManager because ConnectivityManager is initialized before VpnManager. - * @hide TODO: remove. - */ - public VpnManager getVpnManager() { - return mContext.getSystemService(VpnManager.class); - } - /** @hide */ public ConnectivityDiagnosticsManager createDiagnosticsManager() { return new ConnectivityDiagnosticsManager(mContext, mService); diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java index bcb65fab8571..d2ee7d13b05f 100644 --- a/packages/Connectivity/framework/src/android/net/IpPrefix.java +++ b/packages/Connectivity/framework/src/android/net/IpPrefix.java @@ -24,6 +24,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; +import com.android.net.module.util.NetUtils; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -59,7 +61,7 @@ public final class IpPrefix implements Parcelable { throw new IllegalArgumentException( "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); } - NetworkUtils.maskRawAddress(address, prefixLength); + NetUtils.maskRawAddress(address, prefixLength); } /** @@ -190,7 +192,7 @@ public final class IpPrefix implements Parcelable { if (addrBytes == null || addrBytes.length != this.address.length) { return false; } - NetworkUtils.maskRawAddress(addrBytes, prefixLength); + NetUtils.maskRawAddress(addrBytes, prefixLength); return Arrays.equals(this.address, addrBytes); } @@ -204,7 +206,7 @@ public final class IpPrefix implements Parcelable { public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { if (otherPrefix.getPrefixLength() < prefixLength) return false; final byte[] otherAddress = otherPrefix.getRawAddress(); - NetworkUtils.maskRawAddress(otherAddress, prefixLength); + NetUtils.maskRawAddress(otherAddress, prefixLength); return Arrays.equals(otherAddress, address); } diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index 26d14cbfaa95..cd76f409b093 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -205,6 +205,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_OEM_PRIVATE, NET_CAPABILITY_VEHICLE_INTERNAL, NET_CAPABILITY_NOT_VCN_MANAGED, + NET_CAPABILITY_ENTERPRISE, }) public @interface NetCapability { } @@ -415,8 +416,17 @@ public final class NetworkCapabilities implements Parcelable { @SystemApi public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + /** + * Indicates that this network is intended for enterprise use. + * <p> + * 5G URSP rules may indicate that all data should use a connection dedicated for enterprise + * use. If the enterprise capability is requested, all enterprise traffic will be routed over + * the connection with this capability. + */ + public static final int NET_CAPABILITY_ENTERPRISE = 29; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -474,7 +484,8 @@ public final class NetworkCapabilities implements Parcelable { | (1 << NET_CAPABILITY_MCX) | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_XCAP); + | (1 << NET_CAPABILITY_XCAP) + | (1 << NET_CAPABILITY_ENTERPRISE); /** * Capabilities that force network to be restricted. @@ -2028,8 +2039,9 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED"; case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE"; - case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL"; + case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL"; case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED"; + case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE"; default: return Integer.toString(capability); } } diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java index 8be4af7b1396..9ccb04a44af4 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java +++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java @@ -29,7 +29,6 @@ import java.math.BigInteger; import java.net.Inet4Address; import java.net.InetAddress; import java.net.SocketException; -import java.net.UnknownHostException; import java.util.Locale; import java.util.TreeSet; @@ -232,46 +231,6 @@ public class NetworkUtils { } /** - * Masks a raw IP address byte array with the specified prefix length. - */ - public static void maskRawAddress(byte[] array, int prefixLength) { - if (prefixLength < 0 || prefixLength > array.length * 8) { - throw new RuntimeException("IP address with " + array.length + - " bytes has invalid prefix length " + prefixLength); - } - - int offset = prefixLength / 8; - int remainder = prefixLength % 8; - byte mask = (byte)(0xFF << (8 - remainder)); - - if (offset < array.length) array[offset] = (byte)(array[offset] & mask); - - offset++; - - for (; offset < array.length; offset++) { - array[offset] = 0; - } - } - - /** - * Get InetAddress masked with prefixLength. Will never return null. - * @param address the IP address to mask with - * @param prefixLength the prefixLength used to mask the IP - */ - public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { - byte[] array = address.getAddress(); - maskRawAddress(array, prefixLength); - - InetAddress netPart = null; - try { - netPart = InetAddress.getByAddress(array); - } catch (UnknownHostException e) { - throw new RuntimeException("getNetworkPart error - " + e.toString()); - } - return netPart; - } - - /** * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/packages/InputDevices/OWNERS b/packages/InputDevices/OWNERS index 0313a40f7270..f0d6db88bcc5 100644 --- a/packages/InputDevices/OWNERS +++ b/packages/InputDevices/OWNERS @@ -1,2 +1 @@ -michaelwr@google.com -svv@google.com +include /services/core/java/com/android/server/input/OWNERS diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml index 52779bcabf00..85c01c5732ca 100644 --- a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml +++ b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml @@ -19,6 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="match_parent" + android:background="?android:attr/colorBackground" android:orientation="vertical"> <LinearLayout diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java index 74b65780ffc2..1c9298ed6085 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java @@ -17,6 +17,7 @@ package com.android.settingslib.widget; import android.content.Context; +import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -29,6 +30,7 @@ import android.widget.Switch; import android.widget.TextView; import androidx.annotation.VisibleForTesting; +import androidx.core.content.res.TypedArrayUtils; import com.android.settingslib.RestrictedLockUtils; @@ -88,6 +90,17 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec }); setChecked(mSwitch.isChecked()); + + if (attrs != null) { + final TypedArray a = context.obtainStyledAttributes(attrs, + androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/, + 0 /*defStyleRes*/); + final CharSequence title = TypedArrayUtils.getText(a, + androidx.preference.R.styleable.Preference_title, + androidx.preference.R.styleable.Preference_android_title); + setTitle(title); + a.recycle(); + } } @Override @@ -126,7 +139,7 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec /** * Set the title text */ - public void setTitle(String text) { + public void setTitle(CharSequence text) { if (mTextView != null) { mTextView.setText(text); } diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java index 274bf8df2222..35afec38dd3d 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java @@ -18,7 +18,6 @@ package com.android.settingslib.widget; import android.content.Context; import android.content.res.TypedArray; -import android.text.TextUtils; import android.util.AttributeSet; import androidx.core.content.res.TypedArrayUtils; @@ -40,7 +39,7 @@ public class MainSwitchPreference extends TwoStatePreference { private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>(); private MainSwitchBar mMainSwitchBar; - private String mTitle; + private CharSequence mTitle; private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin; @@ -81,24 +80,28 @@ public class MainSwitchPreference extends TwoStatePreference { setLayoutResource(R.layout.main_switch_layout); if (attrs != null) { - TypedArray a = context.obtainStyledAttributes(attrs, + final TypedArray a = context.obtainStyledAttributes(attrs, androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); final CharSequence title = TypedArrayUtils.getText(a, androidx.preference.R.styleable.Preference_title, androidx.preference.R.styleable.Preference_android_title); - if (!TextUtils.isEmpty(title)) { - setTitle(title.toString()); - } + setTitle(title); a.recycle(); } } - /** - * Set the preference title text - */ - public void setTitle(String text) { - mTitle = text; + @Override + public void setChecked(boolean checked) { + super.setChecked(checked); + if (mMainSwitchBar != null) { + mMainSwitchBar.setChecked(checked); + } + } + + @Override + public void setTitle(CharSequence title) { + mTitle = title; if (mMainSwitchBar != null) { mMainSwitchBar.setTitle(mTitle); } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 32419f49d8c9..1f3e0e9fe038 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -205,7 +205,6 @@ public class LocalMediaManager implements BluetoothCallback { void dispatchDeviceListUpdate() { final List<MediaDevice> mediaDevices = new ArrayList<>(mMediaDevices); - Collections.sort(mediaDevices, COMPARATOR); for (DeviceCallback callback : getCallbacks()) { callback.onDeviceListUpdate(mediaDevices); } @@ -472,6 +471,7 @@ public class LocalMediaManager implements BluetoothCallback { synchronized (mMediaDevicesLock) { mMediaDevices.clear(); mMediaDevices.addAll(devices); + Collections.sort(devices, COMPARATOR); // Add disconnected bluetooth devices only when phone output device is available. for (MediaDevice device : devices) { final int type = device.getDeviceType(); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java index 647fd2acf7c8..552fa11a42b7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java @@ -39,8 +39,7 @@ public class MediaOutputConstants { /** * A string extra specifying a media package name. */ - public static final String EXTRA_PACKAGE_NAME = - "com.android.settings.panel.extra.PACKAGE_NAME"; + public static final String EXTRA_PACKAGE_NAME = "package_name"; /** * An intent action to launch media output dialog. diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index ad6a5312f156..66165b6d1ff2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -147,10 +147,5 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR); - VALIDATORS.put( - Global.ONE_HANDED_KEYGUARD_SIDE, - new InclusiveIntegerRangeValidator( - /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT, - /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT)); } } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 303e5bb7050d..664fd4ac2fcb 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -283,7 +283,6 @@ public class SettingsBackupTest { Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS, Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS, Settings.Global.FANCY_IME_ANIMATIONS, - Settings.Global.ONE_HANDED_KEYGUARD_SIDE, Settings.Global.FORCE_ALLOW_ON_EXTERNAL, Settings.Global.FORCED_APP_STANDBY_ENABLED, Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS index 34901f5830c4..6d738f8d4d43 100644 --- a/packages/Shell/OWNERS +++ b/packages/Shell/OWNERS @@ -9,3 +9,4 @@ yamasani@google.com toddke@google.com cbrubaker@google.com omakoto@google.com +michaelwr@google.com diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml index 71cdaf5c7091..79868093fb12 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml @@ -24,7 +24,7 @@ <include style="@style/BouncerSecurityContainer" layout="@layout/keyguard_host_view" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" /> </FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml index c75ee51517d1..04e645bd0a32 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml @@ -41,14 +41,13 @@ android:layout_gravity="center"> <com.android.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" android:paddingTop="@dimen/keyguard_security_view_top_margin" android:paddingStart="@dimen/keyguard_security_view_lateral_margin" android:paddingEnd="@dimen/keyguard_security_view_lateral_margin" - android:layout_gravity="center" android:gravity="center"> </com.android.keyguard.KeyguardSecurityViewFlipper> </com.android.keyguard.KeyguardSecurityContainer> diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml deleted file mode 100644 index e09bf7e37ed0..000000000000 --- a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2021 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources> - <bool name="can_use_one_handed_bouncer">true</bool> -</resources> diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml index 6176f7c1dd0a..8d9d6ee68c67 100644 --- a/packages/SystemUI/res-keyguard/values/config.xml +++ b/packages/SystemUI/res-keyguard/values/config.xml @@ -22,5 +22,4 @@ <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] --> <bool name="config_disableMenuKeyInLockScreen">false</bool> - <bool name="can_use_one_handed_bouncer">false</bool> </resources> diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml index 73beefc9da83..d996cee4b39e 100644 --- a/packages/SystemUI/res/layout/media_output_dialog.xml +++ b/packages/SystemUI/res/layout/media_output_dialog.xml @@ -32,7 +32,8 @@ android:id="@+id/header_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"/> + android:paddingEnd="@dimen/media_output_dialog_header_icon_padding" + android:importantForAccessibility="no"/> <LinearLayout android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4bc5a300e833..89c849a0ef4a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -651,7 +651,7 @@ </dimen> <!-- The height of a notification header --> - <dimen name="notification_header_height">53dp</dimen> + <dimen name="notification_header_height">@*android:dimen/notification_header_height</dimen> <!-- The height of the gap between adjacent notification sections. --> <dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index d4bb128120e9..3e16cd47336c 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -42,4 +42,6 @@ <bool name="flag_lockscreen_animations">false</bool> <bool name="flag_toast_style">false</bool> + + <bool name="flag_navigation_bar_overlay">false</bool> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index f511ed1c69c4..5f6fd30ffa1b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -29,17 +29,12 @@ import android.app.AlertDialog; import android.content.Context; import android.graphics.Insets; import android.graphics.Rect; -import android.provider.Settings; import android.util.AttributeSet; import android.util.MathUtils; import android.util.TypedValue; -import android.view.Gravity; import android.view.MotionEvent; -import android.view.OrientationEventListener; import android.view.VelocityTracker; -import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewPropertyAnimator; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimationControlListener; @@ -60,7 +55,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import java.util.List; @@ -105,12 +99,6 @@ public class KeyguardSecurityContainer extends FrameLayout { private boolean mDisappearAnimRunning; private SwipeListener mSwipeListener; - private boolean mIsSecurityViewLeftAligned = true; - private boolean mOneHandedMode = false; - private SecurityMode mSecurityMode = SecurityMode.Invalid; - private ViewPropertyAnimator mRunningOneHandedAnimator; - private final OrientationEventListener mOrientationEventListener; - private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -169,20 +157,16 @@ public class KeyguardSecurityContainer extends FrameLayout { // Used to notify the container when something interesting happens. public interface SecurityCallback { boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen); - void userActivity(); - void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); /** - * @param strongAuth wheher the user has authenticated with strong authentication like - * pattern, password or PIN but not by trust agents or fingerprint + * @param strongAuth wheher the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint * @param targetUserId a user that needs to be the foreground user at the finish completion. */ void finish(boolean strongAuth, int targetUserId); - void reset(); - void onCancelClicked(); } @@ -240,136 +224,12 @@ public class KeyguardSecurityContainer extends FrameLayout { super(context, attrs, defStyle); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mViewConfiguration = ViewConfiguration.get(context); - - mOrientationEventListener = new OrientationEventListener(context) { - @Override - public void onOrientationChanged(int orientation) { - updateLayoutForSecurityMode(mSecurityMode); - } - }; } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { - mSecurityMode = securityMode; mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); - updateLayoutForSecurityMode(securityMode); - mOrientationEventListener.enable(); - } - - void updateLayoutForSecurityMode(SecurityMode securityMode) { - mSecurityMode = securityMode; - mOneHandedMode = canUseOneHandedBouncer(); - - if (mOneHandedMode) { - mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext); - } - - updateSecurityViewGravity(); - updateSecurityViewLocation(false); - } - - /** Return whether the one-handed keyguard should be enabled. */ - private boolean canUseOneHandedBouncer() { - // Is it enabled? - if (!getResources().getBoolean( - com.android.internal.R.bool.config_enableOneHandedKeyguard)) { - return false; - } - - if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) { - return false; - } - - return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); - } - - /** Read whether the one-handed keyguard should be on the left/right from settings. */ - private boolean isOneHandedKeyguardLeftAligned(Context context) { - try { - return Settings.Global.getInt(context.getContentResolver(), - Settings.Global.ONE_HANDED_KEYGUARD_SIDE) - == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; - } catch (Settings.SettingNotFoundException ex) { - return true; - } - } - - private void updateSecurityViewGravity() { - View securityView = findKeyguardSecurityView(); - - if (securityView == null) { - return; - } - - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams(); - - if (mOneHandedMode) { - lp.gravity = Gravity.LEFT | Gravity.BOTTOM; - } else { - lp.gravity = Gravity.CENTER_HORIZONTAL; - } - - securityView.setLayoutParams(lp); - } - - /** - * Moves the inner security view to the correct location (in one handed mode) with animation. - * This is triggered when the user taps on the side of the screen that is not currently occupied - * by the security view . - */ - private void updateSecurityViewLocation(boolean animate) { - View securityView = findKeyguardSecurityView(); - - if (securityView == null) { - return; - } - - if (!mOneHandedMode) { - securityView.setTranslationX(0); - return; - } - - if (mRunningOneHandedAnimator != null) { - mRunningOneHandedAnimator.cancel(); - mRunningOneHandedAnimator = null; - } - - int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f); - - if (animate) { - mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation); - mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); - mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mRunningOneHandedAnimator = null; - } - }); - - mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); - mRunningOneHandedAnimator.start(); - } else { - securityView.setTranslationX(targetTranslation); - } - } - - @Nullable - private KeyguardSecurityViewFlipper findKeyguardSecurityView() { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - - if (isKeyguardSecurityView(child)) { - return (KeyguardSecurityViewFlipper) child; - } - } - - return null; - } - - private boolean isKeyguardSecurityView(View view) { - return view instanceof KeyguardSecurityViewFlipper; } public void onPause() { @@ -378,7 +238,6 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog = null; } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); - mOrientationEventListener.disable(); } @Override @@ -460,44 +319,19 @@ public class KeyguardSecurityContainer extends FrameLayout { if (mSwipeListener != null) { mSwipeListener.onSwipeUp(); } - } else { - if (!mIsDragging) { - handleTap(event); - } } } return true; } - private void handleTap(MotionEvent event) { - // If we're using a fullscreen security mode, skip - if (!mOneHandedMode) { - return; - } - - // Did the tap hit the "other" side of the bouncer? - if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f)) - || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) { - mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned; - - Settings.Global.putInt( - mContext.getContentResolver(), - Settings.Global.ONE_HANDED_KEYGUARD_SIDE, - mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT - : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); - - updateSecurityViewLocation(true); - } - } - void setSwipeListener(SwipeListener swipeListener) { mSwipeListener = swipeListener; } private void startSpringAnimation(float startVelocity) { mSpringAnimation - .setStartVelocity(startVelocity) - .animateToFinalPosition(0); + .setStartVelocity(startVelocity) + .animateToFinalPosition(0); } public void startDisappearAnimation(SecurityMode securitySelection) { @@ -607,17 +441,18 @@ public class KeyguardSecurityContainer extends FrameLayout { return insets.inset(0, 0, 0, inset); } + private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); } mAlertDialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setCancelable(false) - .setNeutralButton(R.string.ok, null) - .create(); + .setTitle(title) + .setMessage(message) + .setCancelable(false) + .setNeutralButton(R.string.ok, null) + .create(); if (!(mContext instanceof Activity)) { mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); } @@ -655,44 +490,6 @@ public class KeyguardSecurityContainer extends FrameLayout { } } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int maxHeight = 0; - int maxWidth = 0; - int childState = 0; - - int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec) / 2, - MeasureSpec.getMode(widthMeasureSpec)); - - for (int i = 0; i < getChildCount(); i++) { - final View view = getChildAt(i); - if (view.getVisibility() != GONE) { - if (mOneHandedMode && isKeyguardSecurityView(view)) { - measureChildWithMargins(view, halfWidthMeasureSpec, 0, - heightMeasureSpec, 0); - } else { - measureChildWithMargins(view, widthMeasureSpec, 0, - heightMeasureSpec, 0); - } - final LayoutParams lp = (LayoutParams) view.getLayoutParams(); - maxWidth = Math.max(maxWidth, - view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); - maxHeight = Math.max(maxHeight, - view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); - childState = combineMeasuredStates(childState, view.getMeasuredState()); - } - } - - // Check against our minimum height and width - maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); - maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); - - setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), - resolveSizeAndState(maxHeight, heightMeasureSpec, - childState << MEASURED_HEIGHT_STATE_SHIFT)); - } - void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { String message = null; switch (userType) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index fdab8db67431..1a8d420fb394 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -404,7 +404,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); mSecurityViewFlipperController.show(newView); - mView.updateLayoutForSecurityMode(securityMode); } mSecurityCallback.onSecurityModeChanged( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index 631c24844417..c77c86711abf 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -92,13 +92,4 @@ public class KeyguardSecurityModel { throw new IllegalStateException("Unknown security quality:" + security); } } - - /** - * Returns whether the given security view should be used in a "one handed" way. This can be - * used to change how the security view is drawn (e.g. take up less of the screen, and align to - * one side). - */ - public static boolean isSecurityViewOneHanded(SecurityMode securityMode) { - return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN; - } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 27ea64f85b11..70b7b047eebc 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -25,7 +25,6 @@ import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -54,7 +53,6 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -116,7 +114,7 @@ public class NavigationBarController implements Callbacks, // Tracks config changes that will actually recreate the nav bar private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE - | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS + | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_UI_MODE); @Inject @@ -171,6 +169,7 @@ public class NavigationBarController implements Callbacks, configurationController.addCallback(this); mConfigChanges.applyNewConfig(mContext.getResources()); mNavBarOverlayController = navBarOverlayController; + mNavigationModeController.addListener(this); } @Override @@ -188,17 +187,18 @@ public class NavigationBarController implements Callbacks, @Override public void onNavigationModeChanged(int mode) { - // Workaround for b/132825155, for secondary users, we currently don't receive configuration - // changes on overlay package change since SystemUI runs for the system user. In this case, - // trigger a new configuration change to ensure that the nav bar is updated in the same way. - int userId = ActivityManagerWrapper.getInstance().getCurrentUserId(); - if (userId != UserHandle.USER_SYSTEM) { - mHandler.post(() -> { - for (int i = 0; i < mNavigationBars.size(); i++) { - recreateNavigationBar(mNavigationBars.keyAt(i)); + mHandler.post(() -> { + for (int i = 0; i < mNavigationBars.size(); i++) { + NavigationBar navBar = mNavigationBars.valueAt(i); + if (navBar == null) { + continue; } - }); - } + NavigationBarView view = (NavigationBarView) mNavigationBars.get(i).getView(); + if (view != null) { + view.updateStates(); + } + } + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java index c526c5d59552..62b9458447d8 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java @@ -21,6 +21,7 @@ import android.content.Context; import android.view.View; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.FeatureFlags; import java.util.function.Consumer; @@ -31,16 +32,22 @@ import javax.inject.Inject; public class NavigationBarOverlayController { protected final Context mContext; + protected final FeatureFlags mFeatureFlags; @Inject - public NavigationBarOverlayController(Context context) { + public NavigationBarOverlayController(Context context, FeatureFlags featureFlags) { mContext = context; + mFeatureFlags = featureFlags; } public Context getContext() { return mContext; } + public boolean isNavigationBarOverlayEnabled() { + return mFeatureFlags.isNavigationBarOverlayEnabled(); + } + /** * Initialize the controller with visibility change callback and light/dark icon color. */ diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java index b55fa4d612f9..61e1d61e7909 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java @@ -192,6 +192,7 @@ public final class NavigationBarTransitions extends BarTransitions implements buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity); } mView.getRotationButtonController().setDarkIntensity(darkIntensity); + Dependency.get(NavigationBarOverlayController.class).setDarkIntensity(darkIntensity); for (DarkIntensityListener listener : mDarkIntensityListeners) { listener.onDarkIntensity(darkIntensity); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 8e75bec72c15..19e32783f765 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -171,6 +171,7 @@ public class NavigationBarView extends FrameLayout implements private NotificationPanelViewController mPanelView; private FloatingRotationButton mFloatingRotationButton; private RotationButtonController mRotationButtonController; + private NavigationBarOverlayController mNavBarOverlayController; /** * Helper that is responsible for showing the right toast when a disallowed activity operation @@ -339,8 +340,11 @@ public class NavigationBarView extends FrameLayout implements isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton, mRotationButtonListener); - Dependency.get(NavigationBarOverlayController.class).init( - mNavbarOverlayVisibilityChangeCallback, mLightIconColor, mDarkIconColor); + mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class); + if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { + mNavBarOverlayController.init( + mNavbarOverlayVisibilityChangeCallback, mLightIconColor, mDarkIconColor); + } mConfiguration = new Configuration(); mTmpLastConfiguration = new Configuration(); @@ -431,8 +435,9 @@ public class NavigationBarView extends FrameLayout implements // The visibility of the navigation bar buttons is dependent on the transient state of // the navigation bar. - Dependency.get(NavigationBarOverlayController.class).setButtonState( - isTransient, /* force */ false); + if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { + mNavBarOverlayController.setButtonState(isTransient, /* force */ false); + } } void onBarTransition(int newMode) { @@ -666,7 +671,9 @@ public class NavigationBarView extends FrameLayout implements } mImeVisible = visible; mRotationButtonController.getRotationButton().setCanShowRotationButton(!mImeVisible); - Dependency.get(NavigationBarOverlayController.class).setCanShow(!mImeVisible); + if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { + mNavBarOverlayController.setCanShow(!mImeVisible); + } } public void setDisabledFlags(int disabledFlags) { @@ -999,10 +1006,9 @@ public class NavigationBarView extends FrameLayout implements } else { updateButtonLocation(getRotateSuggestionButton(), inScreenSpace); } - final NavigationBarOverlayController navBarButtonsController = - Dependency.get(NavigationBarOverlayController.class); - if (navBarButtonsController.isVisible()) { - updateButtonLocation(navBarButtonsController.getCurrentView(), inScreenSpace); + if (mNavBarOverlayController.isNavigationBarOverlayEnabled() + && mNavBarOverlayController.isVisible()) { + updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace); } return mTmpRegion; } @@ -1230,7 +1236,9 @@ public class NavigationBarView extends FrameLayout implements if (mRotationButtonController != null) { mRotationButtonController.registerListeners(); } - Dependency.get(NavigationBarOverlayController.class).registerListeners(); + if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { + mNavBarOverlayController.registerListeners(); + } getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener); updateNavButtonIcons(); @@ -1247,7 +1255,10 @@ public class NavigationBarView extends FrameLayout implements if (mRotationButtonController != null) { mRotationButtonController.unregisterListeners(); } - Dependency.get(NavigationBarOverlayController.class).unregisterListeners(); + + if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { + mNavBarOverlayController.unregisterListeners(); + } mEdgeBackGestureHandler.onNavBarDetached(); getViewTreeObserver().removeOnComputeInternalInsetsListener( diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 292cc7a7deaa..088743cd0f94 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -93,6 +93,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt( "gestures.back_timeout", 250); + private static final int MAX_NUM_LOGGED_PREDICTIONS = 10; + private static final int MAX_NUM_LOGGED_GESTURES = 10; + // Temporary log until b/176302696 is resolved static final boolean DEBUG_MISSING_GESTURE = true; static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture"; @@ -222,8 +225,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa private String mPackageName; private float mMLResults; - private static final int MAX_LOGGED_PREDICTIONS = 10; + // For debugging private ArrayDeque<String> mPredictionLog = new ArrayDeque<>(); + private ArrayDeque<String> mGestureLog = new ArrayDeque<>(); private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; @@ -607,7 +611,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa } // Check if we are within the tightest bounds beyond which // we would not need to run the ML model. - boolean withinRange = x <= mMLEnableWidth + mLeftInset + boolean withinRange = x < mMLEnableWidth + mLeftInset || x >= (mDisplaySize.x - mMLEnableWidth - mRightInset); if (!withinRange) { int results = -1; @@ -617,17 +621,20 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa // Denotes whether we should proceed with the gesture. // Even if it is false, we may want to log it assuming // it is not invalid due to exclusion. - withinRange = x <= mEdgeWidthLeft + mLeftInset + withinRange = x < mEdgeWidthLeft + mLeftInset || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); } } // For debugging purposes - if (mPredictionLog.size() >= MAX_LOGGED_PREDICTIONS) { + if (mPredictionLog.size() >= MAX_NUM_LOGGED_PREDICTIONS) { mPredictionLog.removeFirst(); } - mPredictionLog.addLast(String.format("[%d,%d,%d,%f,%d]", - x, y, app, mMLResults, withinRange ? 1 : 0)); + mPredictionLog.addLast(String.format("Prediction [%d,%d,%d,%d,%f,%d]", + System.currentTimeMillis(), x, y, app, mMLResults, withinRange ? 1 : 0)); + if (DEBUG_MISSING_GESTURE) { + Log.d(DEBUG_MISSING_GESTURE_TAG, mPredictionLog.peekLast()); + } // Always allow if the user is in a transient sticky immersive state if (mIsNavBarShownTransiently) { @@ -689,6 +696,10 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa private void onMotionEvent(MotionEvent ev) { int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { + if (DEBUG_MISSING_GESTURE) { + Log.d(DEBUG_MISSING_GESTURE_TAG, "Start gesture: " + ev); + } + // Verify if this is in within the touch region and we aren't in immersive mode, and // either the bouncer is showing or the notification panel is hidden mInputEventReceiver.setBatchingEnabled(false); @@ -709,6 +720,19 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa mEndPoint.set(-1, -1); mThresholdCrossed = false; } + + // For debugging purposes + if (mGestureLog.size() >= MAX_NUM_LOGGED_GESTURES) { + mGestureLog.removeFirst(); + } + mGestureLog.addLast(String.format( + "Gesture [%d,alw=%B,%B, %B,%B,disp=%s,wl=%d,il=%d,wr=%d,ir=%d,excl=%s]", + System.currentTimeMillis(), mAllowGesture, mIsOnLeftEdge, mIsBackGestureAllowed, + QuickStepContract.isBackGestureDisabled(mSysUiFlags), mDisplaySize, + mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion)); + if (DEBUG_MISSING_GESTURE) { + Log.d(DEBUG_MISSING_GESTURE_TAG, mGestureLog.peekLast()); + } } else if (mAllowGesture || mLogGesture) { if (!mThresholdCrossed) { mEndPoint.x = (int) ev.getX(); @@ -827,18 +851,29 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa public void dump(PrintWriter pw) { pw.println("EdgeBackGestureHandler:"); pw.println(" mIsEnabled=" + mIsEnabled); + pw.println(" mIsAttached=" + mIsAttached); pw.println(" mIsBackGestureAllowed=" + mIsBackGestureAllowed); + pw.println(" mIsGesturalModeEnabled=" + mIsGesturalModeEnabled); + pw.println(" mIsNavBarShownTransiently=" + mIsNavBarShownTransiently); + pw.println(" mGestureBlockingActivityRunning=" + mGestureBlockingActivityRunning); pw.println(" mAllowGesture=" + mAllowGesture); + pw.println(" mUseMLModel=" + mUseMLModel); pw.println(" mDisabledForQuickstep=" + mDisabledForQuickstep); pw.println(" mStartingQuickstepRotation=" + mStartingQuickstepRotation); pw.println(" mInRejectedExclusion" + mInRejectedExclusion); pw.println(" mExcludeRegion=" + mExcludeRegion); pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion); - pw.println(" mIsAttached=" + mIsAttached); + pw.println(" mPipExcludedBounds=" + mPipExcludedBounds); pw.println(" mEdgeWidthLeft=" + mEdgeWidthLeft); pw.println(" mEdgeWidthRight=" + mEdgeWidthRight); - pw.println(" mIsNavBarShownTransiently=" + mIsNavBarShownTransiently); - pw.println(" mPredictionLog=" + String.join(";", mPredictionLog)); + pw.println(" mLeftInset=" + mLeftInset); + pw.println(" mRightInset=" + mRightInset); + pw.println(" mMLEnableWidth=" + mMLEnableWidth); + pw.println(" mMLModelThreshold=" + mMLModelThreshold); + pw.println(" mTouchSlop=" + mTouchSlop); + pw.println(" mBottomGestureHeight=" + mBottomGestureHeight); + pw.println(" mPredictionLog=" + String.join("\n", mPredictionLog)); + pw.println(" mGestureLog=" + String.join("\n", mGestureLog)); pw.println(" mEdgeBackPlugin=" + mEdgeBackPlugin); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java index 1386ddfa7692..53d9f1c08e6f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java @@ -97,8 +97,8 @@ public class CropView extends View { float bottom = mBottomCrop + mBottomDelta; drawShade(canvas, 0, top); drawShade(canvas, bottom, 1f); - drawHandle(canvas, top); - drawHandle(canvas, bottom); + drawHandle(canvas, top, /* draw the handle tab down */ false); + drawHandle(canvas, bottom, /* draw the handle tab up */ true); } @Override @@ -122,7 +122,7 @@ public class CropView extends View { } else { // Bottom mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta, topPx + 2 * mCropTouchMargin - bottomPx, - getMeasuredHeight() - bottomPx)); + getHeight() - bottomPx)); } updateListener(event); invalidate(); @@ -212,21 +212,25 @@ public class CropView extends View { } private void drawShade(Canvas canvas, float fracStart, float fracEnd) { - canvas.drawRect(0, fractionToPixels(fracStart), getMeasuredWidth(), + canvas.drawRect(0, fractionToPixels(fracStart), getWidth(), fractionToPixels(fracEnd), mShadePaint); } - private void drawHandle(Canvas canvas, float frac) { + private void drawHandle(Canvas canvas, float frac, boolean handleTabUp) { int y = fractionToPixels(frac); - canvas.drawLine(0, y, getMeasuredWidth(), y, mHandlePaint); + canvas.drawLine(0, y, getWidth(), y, mHandlePaint); + float radius = 15 * getResources().getDisplayMetrics().density; + float x = getWidth() * .9f; + canvas.drawArc(x - radius, y - radius, x + radius, y + radius, handleTabUp ? 180 : 0, 180, + true, mHandlePaint); } private int fractionToPixels(float frac) { - return (int) (frac * getMeasuredHeight()); + return (int) (frac * getHeight()); } private float pixelsToFraction(int px) { - return px / (float) getMeasuredHeight(); + return px / (float) getHeight(); } private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index a6433ae94b2b..89efda98a5b6 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -46,6 +46,7 @@ public class LongScreenshotActivity extends Activity { private final UiEventLogger mUiEventLogger; private final ScrollCaptureController mScrollCaptureController; + private final ScrollCaptureClient.Connection mConnection; private ImageView mPreview; private View mSave; @@ -69,8 +70,10 @@ public class LongScreenshotActivity extends Activity { Context context) { mUiEventLogger = uiEventLogger; - mScrollCaptureController = new ScrollCaptureController(context, - ScreenshotController.sScrollConnection, mainExecutor, bgExecutor, imageExporter); + mScrollCaptureController = new ScrollCaptureController(context, mainExecutor, bgExecutor, + imageExporter); + + mConnection = ScreenshotController.takeScrollCaptureConnection(); } @Override @@ -98,15 +101,20 @@ public class LongScreenshotActivity extends Activity { public void onStart() { super.onStart(); if (mPreview.getDrawable() == null) { + if (mConnection == null) { + Log.e(TAG, "Failed to get scroll capture connection, bailing out"); + finishAndRemoveTask(); + return; + } doCapture(); } } - private void disableButtons() { - mSave.setEnabled(false); - mCancel.setEnabled(false); - mEdit.setEnabled(false); - mShare.setEnabled(false); + private void setButtonsEnabled(boolean enabled) { + mSave.setEnabled(enabled); + mCancel.setEnabled(enabled); + mEdit.setEnabled(enabled); + mShare.setEnabled(enabled); } private void doEdit(Uri uri) { @@ -115,8 +123,7 @@ public class LongScreenshotActivity extends Activity { if (!TextUtils.isEmpty(editorPackage)) { intent.setComponent(ComponentName.unflattenFromString(editorPackage)); } - intent.setType("image/png"); - intent.setData(uri); + intent.setDataAndType(uri, "image/png"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); @@ -127,12 +134,11 @@ public class LongScreenshotActivity extends Activity { private void doShare(Uri uri) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/png"); - intent.setData(uri); + intent.putExtra(Intent.EXTRA_STREAM, uri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); Intent sharingChooserIntent = Intent.createChooser(intent, null) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_GRANT_READ_URI_PERMISSION); + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT); } @@ -140,7 +146,7 @@ public class LongScreenshotActivity extends Activity { private void onClicked(View v) { int id = v.getId(); v.setPressed(true); - disableButtons(); + setButtonsEnabled(false); if (id == R.id.save) { startExport(PendingAction.SAVE); } else if (id == R.id.cancel) { @@ -160,10 +166,12 @@ public class LongScreenshotActivity extends Activity { @Override public void onError() { Log.e(TAG, "Error exporting image data."); + setButtonsEnabled(true); } @Override public void onExportComplete(Uri outputUri) { + setButtonsEnabled(true); switch (action) { case EDIT: doEdit(outputUri); @@ -181,7 +189,8 @@ public class LongScreenshotActivity extends Activity { } private void doCapture() { - mScrollCaptureController.start(new ScrollCaptureController.ScrollCaptureCallback() { + mScrollCaptureController.start(mConnection, + new ScrollCaptureController.ScrollCaptureCallback() { @Override public void onError() { Log.e(TAG, "Error!"); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 31c693bdde1f..131fde6b4b56 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -101,7 +101,7 @@ import javax.inject.Inject; public class ScreenshotController { private static final String TAG = logTag(ScreenshotController.class); - public static ScrollCaptureClient.Connection sScrollConnection; + private static ScrollCaptureClient.Connection sScrollConnection; /** * POD used in the AsyncTask which saves an image in the background. @@ -222,6 +222,12 @@ public class ScreenshotController { | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); + public static @Nullable ScrollCaptureClient.Connection takeScrollCaptureConnection() { + ScrollCaptureClient.Connection connection = sScrollConnection; + sScrollConnection = null; + return connection; + } + @Inject ScreenshotController( Context context, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java index 863116a22ee4..4a3ffa45ab81 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java @@ -53,7 +53,6 @@ public class ScrollCaptureController { public static final int MAX_HEIGHT = 12000; - private final Connection mConnection; private final Context mContext; private final Executor mUiExecutor; @@ -65,10 +64,9 @@ public class ScrollCaptureController { private UUID mRequestId; private ScrollCaptureCallback mCaptureCallback; - public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor, - Executor bgExecutor, ImageExporter exporter) { + public ScrollCaptureController(Context context, Executor uiExecutor, Executor bgExecutor, + ImageExporter exporter) { mContext = context; - mConnection = connection; mUiExecutor = uiExecutor; mBgExecutor = bgExecutor; mImageExporter = exporter; @@ -78,16 +76,17 @@ public class ScrollCaptureController { /** * Run scroll capture! * + * @param connection connection to the remote window to be used * @param callback request callback to report back to the service */ - public void start(ScrollCaptureCallback callback) { + public void start(Connection connection, ScrollCaptureCallback callback) { mCaptureTime = ZonedDateTime.now(); mRequestId = UUID.randomUUID(); mCaptureCallback = callback; float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(), SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT); - mConnection.start(this::startCapture, maxPages); + connection.start(this::startCapture, maxPages); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java index 862c27907e0f..cf77e290ebe3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java @@ -82,4 +82,8 @@ public class FeatureFlags { public boolean isMonetEnabled() { return mFlagReader.isEnabled(R.bool.flag_monet); } + + public boolean isNavigationBarOverlayEnabled() { + return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java index f2adaf042b2f..9ed9659c7ab8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java @@ -207,7 +207,7 @@ public class GestureRecorder { sb.append(g.toJson()); count++; } - mLastSaveLen = count; + mLastSaveLen += count; sb.append("]"); return sb.toString(); } @@ -249,7 +249,9 @@ public class GestureRecorder { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { save(); if (mLastSaveLen >= 0) { - pw.println(String.valueOf(mLastSaveLen) + " gestures written to " + mLogfile); + pw.println(String.valueOf(mLastSaveLen) + + " gestures since last dump written to " + mLogfile); + mLastSaveLen = 0; } else { pw.println("error writing gestures"); } 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 041a97e1d404..b25fced6a212 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -78,6 +78,7 @@ import android.media.AudioAttributes; import android.metrics.LogMaker; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -276,7 +277,8 @@ public class StatusBar extends SystemUI implements DemoMode, public static final boolean DEBUG = false; public static final boolean SPEW = false; public static final boolean DUMPTRUCK = true; // extra dumpsys info - public static final boolean DEBUG_GESTURES = false; + public static final boolean DEBUG_GESTURES = Build.IS_DEBUGGABLE; // TODO(b/178277858) + public static final boolean DEBUG_GESTURES_VERBOSE = true; public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false; public static final boolean DEBUG_CAMERA_LIFT = false; @@ -456,9 +458,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final DisplayMetrics mDisplayMetrics; // XXX: gesture research - private final GestureRecorder mGestureRec = DEBUG_GESTURES - ? new GestureRecorder("/sdcard/statusbar_gestures.dat") - : null; + private GestureRecorder mGestureRec = null; private final ScreenPinningRequest mScreenPinningRequest; @@ -856,6 +856,10 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityIntentHelper = new ActivityIntentHelper(mContext); DateTimeView.setReceiverHandler(timeTickHandler); + + if (DEBUG_GESTURES) { + mGestureRec = new GestureRecorder(mContext.getCacheDir() + "/statusbar_gestures.dat"); + } } @Override @@ -2267,7 +2271,7 @@ public class StatusBar extends SystemUI implements DemoMode, public boolean interceptTouchEvent(MotionEvent event) { if (DEBUG_GESTURES) { - if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { + if (DEBUG_GESTURES_VERBOSE || event.getActionMasked() != MotionEvent.ACTION_MOVE) { EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled1, mDisabled2); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 14b4d0262f60..854be1f76722 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -26,16 +26,11 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.testing.TestableResources; -import android.view.View; -import android.view.ViewGroup; import android.view.WindowInsetsController; -import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import org.junit.Before; @@ -50,21 +45,12 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerTest extends SysuiTestCase { - private static final int SCREEN_WIDTH = 1600; - private static final int FAKE_MEASURE_SPEC = - View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY); - - private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN; - private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password; - - @Rule public MockitoRule mRule = MockitoJUnit.rule(); @Mock private WindowInsetsController mWindowInsetsController; - @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; @@ -72,18 +58,9 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Before public void setup() { - // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache - // the real references (rather than the TestableResources that this call creates). - mContext.ensureTestableResources(); - FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); - when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams); mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; - mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } @Test @@ -92,75 +69,4 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(), any(), any()); } - - @Test - public void onMeasure_usesFullWidthWithoutOneHandedMode() { - setUpKeyguard( - /* deviceConfigCanUseOneHandedKeyguard= */false, - /* sysuiResourceCanUseOneHandedKeyguard= */ false, - ONE_HANDED_SECURITY_MODE); - - mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - - verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - } - - @Test - public void onMeasure_usesFullWidthWithDeviceFlagDisabled() { - setUpKeyguard( - /* deviceConfigCanUseOneHandedKeyguard= */false, - /* sysuiResourceCanUseOneHandedKeyguard= */ true, - ONE_HANDED_SECURITY_MODE); - - mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - } - - @Test - public void onMeasure_usesFullWidthWithSysUIFlagDisabled() { - setUpKeyguard( - /* deviceConfigCanUseOneHandedKeyguard= */true, - /* sysuiResourceCanUseOneHandedKeyguard= */ false, - ONE_HANDED_SECURITY_MODE); - - mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - } - - @Test - public void onMeasure_usesHalfWidthWithFlagsEnabled() { - setUpKeyguard( - /* deviceConfigCanUseOneHandedKeyguard= */true, - /* sysuiResourceCanUseOneHandedKeyguard= */ true, - ONE_HANDED_SECURITY_MODE); - - int halfWidthMeasureSpec = - View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY); - mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - - verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC); - } - - @Test - public void onMeasure_usesFullWidthForFullScreenIme() { - setUpKeyguard( - /* deviceConfigCanUseOneHandedKeyguard= */true, - /* sysuiResourceCanUseOneHandedKeyguard= */ true, - TWO_HANDED_SECURITY_MODE); - - mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); - } - - private void setUpKeyguard( - boolean deviceConfigCanUseOneHandedKeyguard, - boolean sysuiResourceCanUseOneHandedKeyguard, - SecurityMode securityMode) { - TestableResources testableResources = mContext.getOrCreateTestableResources(); - testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard, - deviceConfigCanUseOneHandedKeyguard); - testableResources.addOverride(R.bool.can_use_one_handed_bouncer, - sysuiResourceCanUseOneHandedKeyguard); - mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode); - } -} +}
\ No newline at end of file diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java index 6dcad255eee4..3502baa99b6d 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java @@ -23,7 +23,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; -import android.net.ConnectivityManager; +import android.net.VpnManager; import android.os.Bundle; import android.os.UserHandle; import android.provider.Settings; @@ -42,7 +42,7 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity private static final String TAG = "VpnDisconnected"; - private ConnectivityManager mService; + private VpnManager mService; private int mUserId; private String mVpnPackage; @@ -51,8 +51,8 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity super.onCreate(savedInstanceState); mUserId = UserHandle.myUserId(); - final ConnectivityManager cm = getSystemService(ConnectivityManager.class); - mVpnPackage = cm.getAlwaysOnVpnPackageForUser(mUserId); + final VpnManager vm = getSystemService(VpnManager.class); + mVpnPackage = vm.getAlwaysOnVpnPackageForUser(mUserId); if (mVpnPackage == null) { finish(); return; diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java index aab01d03b96d..fb2367843fc1 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java @@ -21,7 +21,6 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import android.content.DialogInterface; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; import android.net.VpnManager; import android.os.Bundle; import android.os.UserHandle; @@ -45,7 +44,6 @@ public class ConfirmDialog extends AlertActivity private String mPackage; - private ConnectivityManager mCm; // TODO: switch entirely to VpnManager once VPN code moves private VpnManager mVm; public ConfirmDialog() { @@ -60,7 +58,6 @@ public class ConfirmDialog extends AlertActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPackage = getCallingPackage(); - mCm = getSystemService(ConnectivityManager.class); mVm = getSystemService(VpnManager.class); if (mVm.prepareVpn(mPackage, null, UserHandle.myUserId())) { @@ -72,7 +69,7 @@ public class ConfirmDialog extends AlertActivity finish(); return; } - final String alwaysOnVpnPackage = mCm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId()); + final String alwaysOnVpnPackage = mVm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId()); // Can't prepare new vpn app when another vpn is always-on if (alwaysOnVpnPackage != null && !alwaysOnVpnPackage.equals(mPackage)) { finish(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index ea1473ea3db7..c63c2e1a257d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -777,6 +777,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); + + if (Binder.getCallingPid() == OWN_PROCESS_ID) { + return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices); + } return getUserStateLocked(resolvedUserId).mInstalledServices; } } diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 76c8d3001158..01055beea4f8 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -1422,7 +1422,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } @Override - public void onDeviceDisconnected(BluetoothDevice device) { + public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) { + Slog.d(LOG_TAG, device.getAddress() + " disconnected w/ reason: (" + reason + ") " + + BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason)); CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress()); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9d86f4eaa520..f4138d10a84d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -188,14 +188,16 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; +import com.android.internal.util.BitUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; import com.android.modules.utils.BasicShellCommandHandler; +import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; import com.android.net.module.util.LinkPropertiesUtils.CompareResult; +import com.android.net.module.util.PermissionUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.AutodestructReference; import com.android.server.connectivity.DataConnectionStats; @@ -1510,7 +1512,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); return getActiveNetworkForUidInternal(uid, ignoreBlocked); } @@ -1533,7 +1535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); final NetworkState state = getUnfilteredActiveNetworkState(uid); filterNetworkStateForUid(state, uid, ignoreBlocked); return state.networkInfo; @@ -1877,7 +1879,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkState[] getAllNetworkState() { // This contains IMSI details, so make sure the caller is privileged. - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); final ArrayList<NetworkState> result = new ArrayList<>(); for (Network network : getAllNetworks()) { @@ -2301,7 +2303,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Public because it's used by mLockdownTracker. public void sendConnectedBroadcast(NetworkInfo info) { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -2565,13 +2567,13 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!checkDumpPermission(mContext, TAG, pw)) return; if (asProto) return; - if (ArrayUtils.contains(args, DIAG_ARG)) { + if (CollectionUtils.contains(args, DIAG_ARG)) { dumpNetworkDiagnostics(pw); return; - } else if (ArrayUtils.contains(args, NETWORK_ARG)) { + } else if (CollectionUtils.contains(args, NETWORK_ARG)) { dumpNetworks(pw); return; - } else if (ArrayUtils.contains(args, REQUEST_ARG)) { + } else if (CollectionUtils.contains(args, REQUEST_ARG)) { dumpNetworkRequests(pw); return; } @@ -2642,7 +2644,7 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println(); - if (ArrayUtils.contains(args, SHORT_ARG) == false) { + if (!CollectionUtils.contains(args, SHORT_ARG)) { pw.println(); pw.println("mNetworkRequestInfoLogs (most recent first):"); pw.increaseIndent(); @@ -4684,7 +4686,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void setGlobalProxy(final ProxyInfo proxyProperties) { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); mProxyTracker.setGlobalProxy(proxyProperties); } @@ -4809,7 +4811,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - if (ArrayUtils.isEmpty(underlyingNetworks)) return null; + if (CollectionUtils.isEmpty(underlyingNetworks)) return null; List<String> interfaces = new ArrayList<>(); for (Network network : underlyingNetworks) { @@ -4853,7 +4855,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!nai.supportsUnderlyingNetworks()) return false; final Network[] underlying = underlyingNetworksOrDefault( nai.networkCapabilities.getOwnerUid(), nai.declaredUnderlyingNetworks); - return ArrayUtils.contains(underlying, network); + return CollectionUtils.contains(underlying, network); } /** @@ -4886,7 +4888,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS, encodeBool(requireVpn), 0 /* arg2 */, ranges)); } @@ -5317,8 +5319,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - // TODO: use NetworkStackUtils.convertToIntArray after moving it - return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds)); + return CollectionUtils.toIntArray(new ArrayList<>(thresholds)); } private void updateSignalStrengthThresholds( @@ -6437,7 +6438,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) { underlyingNetworks = underlyingNetworksOrDefault( agentCaps.getOwnerUid(), underlyingNetworks); - int[] transportTypes = agentCaps.getTransportTypes(); + long transportTypes = BitUtils.packBits(agentCaps.getTransportTypes()); int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; // metered if any underlying is metered, or originally declared metered by the agent. @@ -6456,7 +6457,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities underlyingCaps = underlying.networkCapabilities; hadUnderlyingNetworks = true; for (int underlyingType : underlyingCaps.getTransportTypes()) { - transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType); + transportTypes |= 1L << underlyingType; } // Merge capabilities of this underlying network. For bandwidth, assume the @@ -6487,7 +6488,7 @@ public class ConnectivityService extends IConnectivityManager.Stub suspended = false; } - newNc.setTransportTypes(transportTypes); + newNc.setTransportTypes(BitUtils.unpackBits(transportTypes)); newNc.setLinkDownstreamBandwidthKbps(downKbps); newNc.setLinkUpstreamBandwidthKbps(upKbps); newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered); @@ -8552,14 +8553,14 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo virtual : mNetworkAgentInfos) { if (virtual.supportsUnderlyingNetworks() && virtual.networkCapabilities.getOwnerUid() == callbackUid - && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) { + && CollectionUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) { return true; } } // Administrator UIDs also contains the Owner UID final int[] administratorUids = nai.networkCapabilities.getAdministratorUids(); - return ArrayUtils.contains(administratorUids, callbackUid); + return CollectionUtils.contains(administratorUids, callbackUid); } @Override diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index 88ce2208adcb..e29e894a5cc0 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -28,6 +28,7 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.image.IDynamicSystemService; +import android.os.storage.DiskInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.Slog; @@ -40,6 +41,7 @@ import java.io.File; */ public class DynamicSystemService extends IDynamicSystemService.Stub { private static final String TAG = "DynamicSystemService"; + private static final long MINIMUM_SD_MB = (30L << 10); private static final int GSID_ROUGH_TIMEOUT_MS = 8192; private static final String PATH_DEFAULT = "/data/gsi/"; private Context mContext; @@ -95,6 +97,13 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { if (!volume.isMountedWritable()) { continue; } + DiskInfo disk = volume.getDisk(); + long mega = disk.size >> 20; + Slog.i(TAG, volume.getPath() + ": " + mega + " MB"); + if (mega < MINIMUM_SD_MB) { + Slog.i(TAG, volume.getPath() + ": insufficient storage"); + continue; + } File sd_internal = volume.getInternalPathForUser(userId); if (sd_internal != null) { path = new File(sd_internal, dsuSlot).getPath(); diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index b48bc900aa84..81d4b9da63c8 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -48,7 +48,6 @@ import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -64,6 +63,7 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.net.module.util.NetdUtils; import libcore.io.IoUtils; @@ -117,9 +117,6 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; - /* NetworkManager instance */ - private final INetworkManagementService mNetworkManager; - /** * The next non-repeating global ID for tracking resources between users, this service, and * kernel data structures. Accessing this variable is not thread safe, so it is only read or @@ -1014,13 +1011,13 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context, INetworkManagementService networkManager) { - this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE); + private IpSecService(Context context) { + this(context, IpSecServiceConfiguration.GETSRVINSTANCE); } - static IpSecService create(Context context, INetworkManagementService networkManager) + static IpSecService create(Context context) throws InterruptedException { - final IpSecService service = new IpSecService(context, networkManager); + final IpSecService service = new IpSecService(context); service.connectNativeNetdService(); return service; } @@ -1034,11 +1031,9 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, INetworkManagementService networkManager, - IpSecServiceConfiguration config) { + public IpSecService(Context context, IpSecServiceConfiguration config) { this( context, - networkManager, config, (fd, uid) -> { try { @@ -1052,10 +1047,9 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, INetworkManagementService networkManager, - IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { + public IpSecService(Context context, IpSecServiceConfiguration config, + UidFdTagger uidFdTagger) { mContext = context; - mNetworkManager = Objects.requireNonNull(networkManager); mSrvConfig = config; mUidFdTagger = uidFdTagger; } @@ -1335,7 +1329,7 @@ public class IpSecService extends IIpSecService.Stub { netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); Binder.withCleanCallingIdentity(() -> { - mNetworkManager.setInterfaceUp(intfName); + NetdUtils.setInterfaceUp(netd, intfName); }); for (int selAddrFamily : ADDRESS_FAMILIES) { diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 329ab9983c90..8d5d3d939e4b 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; + import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -837,7 +839,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo)) { - Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); + Binder.withCleanCallingIdentity( + () -> + cbInfo.mCallback.onVcnStatusChanged( + VCN_STATUS_CODE_SAFE_MODE)); } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5ee0e040019c..29b85acc6825 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -173,6 +173,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; +import android.app.PropertyInvalidatedCache; import android.app.WaitResult; import android.app.backup.BackupManager.OperationType; import android.app.backup.IBackupManager; @@ -181,7 +182,6 @@ import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; -import android.compat.Compatibility; import android.content.AutofillOptions; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; @@ -306,7 +306,6 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.app.ProcessMap; import com.android.internal.app.SystemUserHomeActivity; import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -6083,10 +6082,18 @@ public class ActivityManagerService extends IActivityManager.Stub abiOverride, zygotePolicyFlags); } - // TODO: Move to ProcessList? @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, boolean disableHiddenApiChecks, String abiOverride, int zygotePolicyFlags) { + return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks, + false /* disableTestApiChecks */, abiOverride, zygotePolicyFlags); + } + + // TODO: Move to ProcessList? + @GuardedBy("this") + final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, + boolean disableHiddenApiChecks, boolean disableTestApiChecks, + String abiOverride, int zygotePolicyFlags) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -6121,7 +6128,8 @@ public class ActivityManagerService extends IActivityManager.Stub mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, new HostingRecord("added application", customProcess != null ? customProcess : app.processName), - zygotePolicyFlags, disableHiddenApiChecks, abiOverride); + zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, + abiOverride); } return app; @@ -9863,6 +9871,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (thread != null) { pw.println("\n\n** Cache info for pid " + pid + " [" + r.processName + "] **"); pw.flush(); + if (pid == MY_PID) { + PropertyInvalidatedCache.dumpCacheInfo(fd, args); + continue; + } try { TransferPipe tp = new TransferPipe(); try { @@ -13557,8 +13569,6 @@ public class ActivityManagerService extends IActivityManager.Stub if (disableHiddenApiChecks || disableTestApiChecks) { enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS, "disable hidden API checks"); - - enableTestApiAccess(ai.packageName); } final long origId = Binder.clearCallingIdentity(); @@ -13576,8 +13586,8 @@ public class ActivityManagerService extends IActivityManager.Stub mUsageStatsService.reportEvent(ii.targetPackage, userId, UsageEvents.Event.SYSTEM_INTERACTION); } - app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, abiOverride, - ZYGOTE_POLICY_FLAG_EMPTY); + app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, + disableTestApiChecks, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY); } app.setActiveInstrumentation(activeInstr); @@ -13732,25 +13742,6 @@ public class ActivityManagerService extends IActivityManager.Stub app.userId, "finished inst"); } - - disableTestApiAccess(app.info.packageName); - } - - private void enableTestApiAccess(String packageName) { - if (mPlatformCompat != null) { - Compatibility.ChangeConfig config = new Compatibility.ChangeConfig( - Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */), - Collections.emptySet()); - CompatibilityChangeConfig override = new CompatibilityChangeConfig(config); - mPlatformCompat.setOverridesForTest(override, packageName); - } - } - - private void disableTestApiAccess(String packageName) { - if (mPlatformCompat != null) { - mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */, - packageName); - } } public void finishInstrumentation(IApplicationThread target, diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 7bdf43c9c744..a34163cd5fa2 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -66,6 +66,10 @@ public final class CachedAppOptimizer { @VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4"; @VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5"; @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6"; + @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MIN_OOM_ADJ = + "compact_throttle_min_oom_adj"; + @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MAX_OOM_ADJ = + "compact_throttle_max_oom_adj"; @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; @VisibleForTesting static final String KEY_FREEZER_STATSD_SAMPLE_RATE = @@ -101,6 +105,10 @@ public final class CachedAppOptimizer { @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000; + @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ = + ProcessList.CACHED_APP_MIN_ADJ; + @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ = + ProcessList.CACHED_APP_MAX_ADJ; // The sampling rate to push app compaction events into statsd for upload. @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f; @VisibleForTesting static final long DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB = 12_000L; @@ -186,6 +194,10 @@ public final class CachedAppOptimizer { updateFullDeltaRssThrottle(); } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) { updateProcStateThrottle(); + } else if (KEY_COMPACT_THROTTLE_MIN_OOM_ADJ.equals(name)) { + updateMinOomAdjThrottle(); + } else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) { + updateMaxOomAdjThrottle(); } } } @@ -217,6 +229,12 @@ public final class CachedAppOptimizer { @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mCompactThrottleMinOomAdj = + DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mCompactThrottleMaxOomAdj = + DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; + @GuardedBy("mPhenotypeFlagLock") private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER; @GuardedBy("this") @@ -282,6 +300,7 @@ public final class CachedAppOptimizer { * starts the background thread if necessary. */ public void init() { + // TODO: initialize flags to default and only update them if values are set in DeviceConfig DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener); synchronized (mPhenotypeFlagLock) { @@ -294,6 +313,8 @@ public final class CachedAppOptimizer { updateFullDeltaRssThrottle(); updateProcStateThrottle(); updateUseFreezer(); + updateMinOomAdjThrottle(); + updateMaxOomAdjThrottle(); } } @@ -328,6 +349,8 @@ public final class CachedAppOptimizer { pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull); pw.println(" " + KEY_COMPACT_THROTTLE_5 + "=" + mCompactThrottleBFGS); pw.println(" " + KEY_COMPACT_THROTTLE_6 + "=" + mCompactThrottlePersistent); + pw.println(" " + KEY_COMPACT_THROTTLE_MIN_OOM_ADJ + "=" + mCompactThrottleMinOomAdj); + pw.println(" " + KEY_COMPACT_THROTTLE_MAX_OOM_ADJ + "=" + mCompactThrottleMaxOomAdj); pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mCompactStatsdSampleRate); pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "=" + mFullAnonRssThrottleKb); @@ -367,12 +390,23 @@ public final class CachedAppOptimizer { @GuardedBy("mProcLock") void compactAppFull(ProcessRecord app) { - app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_FULL); - mPendingCompactionProcesses.add(app); - mCompactionHandler.sendMessage( + // Apply OOM adj score throttle for Full App Compaction. + if ((app.mState.getSetAdj() < mCompactThrottleMinOomAdj + || app.mState.getSetAdj() > mCompactThrottleMaxOomAdj) + && app.mState.getCurAdj() >= mCompactThrottleMinOomAdj + && app.mState.getCurAdj() <= mCompactThrottleMaxOomAdj) { + app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_FULL); + mPendingCompactionProcesses.add(app); + mCompactionHandler.sendMessage( mCompactionHandler.obtainMessage( - COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState())); - + COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState())); + } else { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping full compaction for " + app.processName + + " oom adj score changed from " + app.mState.getSetAdj() + + " to " + app.mState.getCurAdj()); + } + } } @GuardedBy("mProcLock") @@ -629,6 +663,7 @@ public final class CachedAppOptimizer { @GuardedBy("mPhenotypeFlagLock") private void updateCompactionThrottles() { boolean useThrottleDefaults = false; + // TODO: improve efficiency by calling DeviceConfig only once for all flags. String throttleSomeSomeFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_THROTTLE_1); @@ -647,12 +682,20 @@ public final class CachedAppOptimizer { String throttlePersistentFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_THROTTLE_6); + String throttleMinOomAdjFlag = + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_MIN_OOM_ADJ); + String throttleMaxOomAdjFlag = + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_MAX_OOM_ADJ); if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag) || TextUtils.isEmpty(throttleFullSomeFlag) || TextUtils.isEmpty(throttleFullFullFlag) || TextUtils.isEmpty(throttleBFGSFlag) - || TextUtils.isEmpty(throttlePersistentFlag)) { + || TextUtils.isEmpty(throttlePersistentFlag) + || TextUtils.isEmpty(throttleMinOomAdjFlag) + || TextUtils.isEmpty(throttleMaxOomAdjFlag)) { // Set defaults for all if any are not set. useThrottleDefaults = true; } else { @@ -663,6 +706,8 @@ public final class CachedAppOptimizer { mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag); mCompactThrottleBFGS = Integer.parseInt(throttleBFGSFlag); mCompactThrottlePersistent = Integer.parseInt(throttlePersistentFlag); + mCompactThrottleMinOomAdj = Long.parseLong(throttleMinOomAdjFlag); + mCompactThrottleMaxOomAdj = Long.parseLong(throttleMaxOomAdjFlag); } catch (NumberFormatException e) { useThrottleDefaults = true; } @@ -675,6 +720,8 @@ public final class CachedAppOptimizer { mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5; mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; + mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; + mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; } } @@ -729,6 +776,28 @@ public final class CachedAppOptimizer { } } + @GuardedBy("mPhenotypeFlagLock") + private void updateMinOomAdjThrottle() { + mCompactThrottleMinOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ); + + // Should only compact cached processes. + if (mCompactThrottleMinOomAdj < ProcessList.CACHED_APP_MIN_ADJ) { + mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; + } + } + + @GuardedBy("mPhenotypeFlagLock") + private void updateMaxOomAdjThrottle() { + mCompactThrottleMaxOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ); + + // Should only compact cached processes. + if (mCompactThrottleMaxOomAdj > ProcessList.CACHED_APP_MAX_ADJ) { + mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; + } + } + private boolean parseProcStateThrottle(String procStateThrottleString) { String[] procStates = TextUtils.split(procStateThrottleString, ","); mProcStateThrottle.clear(); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 0a8016cf0556..87cba54678c4 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -2541,9 +2541,7 @@ public final class OomAdjuster { && (state.getCurAdj() == ProcessList.PREVIOUS_APP_ADJ || state.getCurAdj() == ProcessList.HOME_APP_ADJ)) { mCachedAppOptimizer.compactAppSome(app); - } else if ((state.getSetAdj() < ProcessList.CACHED_APP_MIN_ADJ - || state.getSetAdj() > ProcessList.CACHED_APP_MAX_ADJ) - && state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ + } else if (state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ && state.getCurAdj() <= ProcessList.CACHED_APP_MAX_ADJ) { mCachedAppOptimizer.compactAppFull(app); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 194736fbf911..cb07a06d8340 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1759,7 +1759,8 @@ public final class ProcessList { */ @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, - int zygotePolicyFlags, boolean disableHiddenApiChecks, String abiOverride) { + int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, + String abiOverride) { if (app.isPendingStart()) { return true; } @@ -1905,6 +1906,10 @@ public final class ProcessList { throw new IllegalStateException("Invalid API policy: " + policy); } runtimeFlags |= policyBits; + + if (disableTestApiChecks) { + runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY; + } } String useAppImageCache = SystemProperties.get( @@ -2368,7 +2373,8 @@ public final class ProcessList { boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, - false /* disableHiddenApiChecks */, abiOverride); + false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, + abiOverride); } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java index e97f0b47380a..33bdac270c53 100644 --- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -23,9 +23,12 @@ import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION; +import static com.android.server.apphibernation.AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityThread; import android.app.IActivityManager; import android.apphibernation.IAppHibernationService; import android.content.BroadcastReceiver; @@ -45,6 +48,8 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -93,6 +98,9 @@ public final class AppHibernationService extends SystemService { private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore; private final Injector mInjector; + @VisibleForTesting + boolean mIsServiceEnabled; + /** * Initializes the system service. * <p> @@ -139,6 +147,13 @@ public final class AppHibernationService extends SystemService { initializeGlobalHibernationStates(states); } } + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + mIsServiceEnabled = isAppHibernationEnabled(); + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_APP_HIBERNATION, + ActivityThread.currentApplication().getMainExecutor(), + this::onDeviceConfigChanged); + } } /** @@ -149,6 +164,10 @@ public final class AppHibernationService extends SystemService { * @return true if package is hibernating for the user */ boolean isHibernatingForUser(String packageName, int userId) { + if (!checkHibernationEnabled("isHibernatingForUser")) { + return false; + } + userId = handleIncomingUser(userId, "isHibernating"); if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user " @@ -174,6 +193,9 @@ public final class AppHibernationService extends SystemService { * @param packageName package to check */ boolean isHibernatingGlobally(String packageName) { + if (!checkHibernationEnabled("isHibernatingGlobally")) { + return false; + } synchronized (mLock) { GlobalLevelState state = mGlobalHibernationStates.get(packageName); if (state == null) { @@ -192,6 +214,9 @@ public final class AppHibernationService extends SystemService { * @param isHibernating new hibernation state */ void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { + if (!checkHibernationEnabled("setHibernatingForUser")) { + return; + } userId = handleIncomingUser(userId, "setHibernating"); if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user " @@ -229,6 +254,9 @@ public final class AppHibernationService extends SystemService { * @param isHibernating new hibernation state */ void setHibernatingGlobally(String packageName, boolean isHibernating) { + if (!checkHibernationEnabled("setHibernatingGlobally")) { + return; + } synchronized (mLock) { GlobalLevelState state = mGlobalHibernationStates.get(packageName); if (state == null) { @@ -421,6 +449,9 @@ public final class AppHibernationService extends SystemService { private void onPackageAdded(@NonNull String packageName, int userId) { synchronized (mLock) { + if (!mUserStates.contains(userId)) { + return; + } UserLevelState userState = new UserLevelState(); userState.packageName = packageName; mUserStates.get(userId).put(packageName, userState); @@ -434,6 +465,9 @@ public final class AppHibernationService extends SystemService { private void onPackageRemoved(@NonNull String packageName, int userId) { synchronized (mLock) { + if (!mUserStates.contains(userId)) { + return; + } mUserStates.get(userId).remove(packageName); } } @@ -444,6 +478,15 @@ public final class AppHibernationService extends SystemService { } } + private void onDeviceConfigChanged(Properties properties) { + for (String key : properties.getKeyset()) { + if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) { + mIsServiceEnabled = isAppHibernationEnabled(); + break; + } + } + } + /** * Private helper method to get the real user id and enforce permission checks. * @@ -461,6 +504,13 @@ public final class AppHibernationService extends SystemService { } } + private boolean checkHibernationEnabled(String methodName) { + if (!mIsServiceEnabled) { + Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName)); + } + return mIsServiceEnabled; + } + private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this); static final class AppHibernationServiceStub extends IAppHibernationService.Stub { @@ -536,7 +586,7 @@ public final class AppHibernationService extends SystemService { public static boolean isAppHibernationEnabled() { return DeviceConfig.getBoolean( NAMESPACE_APP_HIBERNATION, - AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED, + KEY_APP_HIBERNATION_ENABLED, false /* defaultValue */); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5f3405379715..f5b94177a2d9 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -8570,6 +8570,7 @@ public class AudioService extends IAudioService.Stub public void postDisplaySafeVolumeWarning(int flags) { if (mController == null) return; + flags = flags | AudioManager.FLAG_SHOW_UI; try { mController.displaySafeVolumeWarning(flags); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java new file mode 100644 index 000000000000..f35a5208f6ed --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/ReEnrollNotificationUtils.java @@ -0,0 +1,82 @@ +/* + * 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.biometrics.sensors.face; + +import android.annotation.NonNull; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; + +import com.android.internal.R; + +public class ReEnrollNotificationUtils { + + private static final String NOTIFICATION_TAG = "FaceService"; + private static final int NOTIFICATION_ID = 1; + + public static void showReEnrollmentNotification(@NonNull Context context) { + final NotificationManager notificationManager = + context.getSystemService(NotificationManager.class); + + final String name = + context.getString(R.string.face_recalibrate_notification_name); + final String title = + context.getString(R.string.face_recalibrate_notification_title); + final String content = + context.getString(R.string.face_recalibrate_notification_content); + + final Intent intent = new Intent("android.settings.FACE_SETTINGS"); + intent.setPackage("com.android.settings"); + + final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, + 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, + null /* options */, UserHandle.CURRENT); + + final String channelName = "FaceEnrollNotificationChannel"; + + final NotificationChannel channel = new NotificationChannel(channelName, name, + NotificationManager.IMPORTANCE_HIGH); + final Notification notification = new Notification.Builder(context, channelName) + .setSmallIcon(R.drawable.ic_lock) + .setContentTitle(title) + .setContentText(content) + .setSubText(name) + .setOnlyAlertOnce(true) + .setLocalOnly(true) + .setAutoCancel(true) + .setCategory(Notification.CATEGORY_SYSTEM) + .setContentIntent(pendingIntent) + .setVisibility(Notification.VISIBILITY_SECRET) + .build(); + + notificationManager.createNotificationChannel(channel); + notificationManager.notifyAsUser(NOTIFICATION_TAG, + NOTIFICATION_ID, notification, + UserHandle.CURRENT); + } + + public static void cancelNotification(@NonNull Context context) { + final NotificationManager notificationManager = + context.getSystemService(NotificationManager.class); + notificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, UserHandle.CURRENT); + } + +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index 8f554028ebfd..089cf1e4cee8 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -41,6 +41,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutCache; import com.android.server.biometrics.sensors.LockoutConsumer; import com.android.server.biometrics.sensors.LockoutTracker; +import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils; import com.android.server.biometrics.sensors.face.UsageStats; import java.util.ArrayList; @@ -163,6 +164,9 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements vibrateError(); } break; + case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL: + ReEnrollNotificationUtils.showReEnrollmentNotification(getContext()); + break; default: break; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java index 898d81b0c8c4..0eb51fdba159 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java @@ -41,6 +41,7 @@ import com.android.server.biometrics.sensors.BiometricUtils; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnrollClient; import com.android.server.biometrics.sensors.face.FaceUtils; +import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils; import java.io.IOException; import java.util.ArrayList; @@ -85,6 +86,13 @@ public class FaceEnrollClient extends EnrollClient<ISession> { } @Override + public void start(@NonNull Callback callback) { + super.start(callback); + + ReEnrollNotificationUtils.cancelNotification(getContext()); + } + + @Override public void destroy() { try { AidlNativeHandleUtils.close(mPreviewSurface); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index ee8823e041bc..1b9bd7fd0cea 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -19,7 +19,6 @@ package com.android.server.biometrics.sensors.face.hidl; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.NotificationManager; import android.app.SynchronousUserSwitchObserver; import android.app.UserSwitchObserver; import android.content.Context; @@ -71,6 +70,7 @@ import com.android.server.biometrics.sensors.PerformanceTracker; import com.android.server.biometrics.sensors.RemovalConsumer; import com.android.server.biometrics.sensors.face.FaceUtils; import com.android.server.biometrics.sensors.face.LockoutHalImpl; +import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils; import com.android.server.biometrics.sensors.face.ServiceProvider; import com.android.server.biometrics.sensors.face.UsageStats; @@ -96,8 +96,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { private static final String TAG = "Face10"; private static final int ENROLL_TIMEOUT_SEC = 75; - static final String NOTIFICATION_TAG = "FaceService"; - static final int NOTIFICATION_ID = 1; private boolean mTestHalEnabled; @@ -109,7 +107,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final LockoutHalImpl mLockoutTracker; @NonNull private final UsageStats mUsageStats; - @NonNull private final NotificationManager mNotificationManager; @NonNull private final Map<Integer, Long> mAuthenticatorIds; @Nullable private IBiometricsFace mDaemon; @NonNull private final HalResultController mHalResultController; @@ -343,7 +340,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { mUsageStats = new UsageStats(context); mAuthenticatorIds = new HashMap<>(); mLazyDaemon = Face10.this::getDaemon; - mNotificationManager = mContext.getSystemService(NotificationManager.class); mLockoutTracker = new LockoutHalImpl(); mLockoutResetDispatcher = lockoutResetDispatcher; mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler, @@ -607,8 +603,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); - mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, - UserHandle.CURRENT); + ReEnrollNotificationUtils.cancelNotification(mContext); final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java index a4b3ac57a4df..3ca51d32797e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java @@ -17,12 +17,7 @@ package com.android.server.biometrics.sensors.face.hidl; import android.annotation.NonNull; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Context; -import android.content.Intent; import android.content.res.Resources; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; @@ -32,7 +27,6 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.face.FaceManager; import android.os.IBinder; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Slog; import com.android.internal.R; @@ -40,6 +34,7 @@ import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutTracker; +import com.android.server.biometrics.sensors.face.ReEnrollNotificationUtils; import com.android.server.biometrics.sensors.face.UsageStats; import java.util.ArrayList; @@ -52,7 +47,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { private static final String TAG = "FaceAuthenticationClient"; - private final NotificationManager mNotificationManager; + private final UsageStats mUsageStats; private final int[] mBiometricPromptIgnoreList; @@ -72,7 +67,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, lockoutTracker, isKeyguard); - mNotificationManager = context.getSystemService(NotificationManager.class); mUsageStats = usageStats; final Resources resources = getContext().getResources(); @@ -188,41 +182,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { mLastAcquire = acquireInfo; if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) { - final String name = - getContext().getString(R.string.face_recalibrate_notification_name); - final String title = - getContext().getString(R.string.face_recalibrate_notification_title); - final String content = - getContext().getString(R.string.face_recalibrate_notification_content); - - final Intent intent = new Intent("android.settings.FACE_SETTINGS"); - intent.setPackage("com.android.settings"); - - final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(getContext(), - 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, - null /* options */, UserHandle.CURRENT); - - final String channelName = "FaceEnrollNotificationChannel"; - - NotificationChannel channel = new NotificationChannel(channelName, name, - NotificationManager.IMPORTANCE_HIGH); - Notification notification = new Notification.Builder(getContext(), channelName) - .setSmallIcon(R.drawable.ic_lock) - .setContentTitle(title) - .setContentText(content) - .setSubText(name) - .setOnlyAlertOnce(true) - .setLocalOnly(true) - .setAutoCancel(true) - .setCategory(Notification.CATEGORY_SYSTEM) - .setContentIntent(pendingIntent) - .setVisibility(Notification.VISIBILITY_SECRET) - .build(); - - mNotificationManager.createNotificationChannel(channel); - mNotificationManager.notifyAsUser(Face10.NOTIFICATION_TAG, - Face10.NOTIFICATION_ID, notification, - UserHandle.CURRENT); + ReEnrollNotificationUtils.showReEnrollmentNotification(getContext()); } final boolean shouldSend = shouldSend(acquireInfo, vendorCode); diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 46c49e7fc28c..641287f0f435 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -16,6 +16,8 @@ package com.android.server.connectivity; +import static com.android.net.module.util.CollectionUtils.contains; + import android.annotation.NonNull; import android.net.ConnectivityManager; import android.net.IDnsResolver; @@ -33,7 +35,6 @@ import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkStackConstants; import com.android.server.net.BaseNetworkObserver; @@ -117,8 +118,8 @@ public class Nat464Xlat extends BaseNetworkObserver { @VisibleForTesting protected static boolean requiresClat(NetworkAgentInfo nai) { // TODO: migrate to NetworkCapabilities.TRANSPORT_*. - final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType()); - final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState()); + final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType()); + final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState()); // Only run clat on networks that have a global IPv6 address and don't have a native IPv4 // address. diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 8bf188696c27..9411e33434d8 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -28,6 +28,8 @@ import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; +import static com.android.net.module.util.CollectionUtils.toIntArray; + import android.annotation.NonNull; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -40,23 +42,21 @@ import android.net.UidRange; import android.os.Build; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; import android.system.OsConstants; -import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.CollectionUtils; import com.android.server.LocalServices; -import com.android.server.SystemConfig; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -80,6 +80,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse private final PackageManager mPackageManager; private final UserManager mUserManager; + private final SystemConfigManager mSystemConfigManager; private final INetd mNetd; private final Dependencies mDeps; @@ -123,6 +124,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse @NonNull final Dependencies deps) { mPackageManager = context.getPackageManager(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mSystemConfigManager = context.getSystemService(SystemConfigManager.class); mNetd = netd; mDeps = deps; } @@ -174,20 +176,18 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */)); - final SparseArray<ArraySet<String>> systemPermission = - SystemConfig.getInstance().getSystemPermissions(); - for (int i = 0; i < systemPermission.size(); i++) { - ArraySet<String> perms = systemPermission.valueAt(i); - int uid = systemPermission.keyAt(i); - int netdPermission = 0; - // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission. - if (perms != null) { - netdPermission |= perms.contains(UPDATE_DEVICE_STATS) - ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0; - netdPermission |= perms.contains(INTERNET) - ? INetd.PERMISSION_INTERNET : 0; + final SparseArray<String> netdPermToSystemPerm = new SparseArray<>(); + netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET); + netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS); + for (int i = 0; i < netdPermToSystemPerm.size(); i++) { + final int netdPermission = netdPermToSystemPerm.keyAt(i); + final String systemPermission = netdPermToSystemPerm.valueAt(i); + final int[] hasPermissionUids = + mSystemConfigManager.getSystemPermissionUids(systemPermission); + for (int j = 0; j < hasPermissionUids.length; j++) { + final int uid = hasPermissionUids[j]; + netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); } - netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); } log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); update(mUsers, mApps, true); @@ -204,7 +204,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) { return false; } - final int index = ArrayUtils.indexOf(app.requestedPermissions, permission); + final int index = CollectionUtils.indexOf(app.requestedPermissions, permission); if (index < 0 || index >= app.requestedPermissionsFlags.length) return false; return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0; } @@ -246,15 +246,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse return mApps.containsKey(uid); } - private int[] toIntArray(Collection<Integer> list) { - int[] array = new int[list.size()]; - int i = 0; - for (Integer item : list) { - array[i++] = item; - } - return array; - } - private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) { List<Integer> network = new ArrayList<>(); List<Integer> system = new ArrayList<>(); @@ -662,23 +653,23 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse if (allPermissionAppIds.size() != 0) { mNetd.trafficSetNetPermForUids( INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, - ArrayUtils.convertToIntArray(allPermissionAppIds)); + toIntArray(allPermissionAppIds)); } if (internetPermissionAppIds.size() != 0) { mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET, - ArrayUtils.convertToIntArray(internetPermissionAppIds)); + toIntArray(internetPermissionAppIds)); } if (updateStatsPermissionAppIds.size() != 0) { mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS, - ArrayUtils.convertToIntArray(updateStatsPermissionAppIds)); + toIntArray(updateStatsPermissionAppIds)); } if (noPermissionAppIds.size() != 0) { mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE, - ArrayUtils.convertToIntArray(noPermissionAppIds)); + toIntArray(noPermissionAppIds)); } if (uninstalledAppIds.size() != 0) { mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED, - ArrayUtils.convertToIntArray(uninstalledAppIds)); + toIntArray(uninstalledAppIds)); } } catch (RemoteException e) { Log.e(TAG, "Pass appId list of special permission failed." + e); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index a769e88f77d7..01ac81fb2cb5 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -113,6 +113,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; +import com.android.net.module.util.NetdUtils; import com.android.net.module.util.NetworkStackConstants; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; @@ -1509,7 +1510,7 @@ public class Vpn { if (start != -1) ranges.add(new UidRange(start, stop)); } else if (disallowedApplications != null) { // Add all ranges for user skipping UIDs for disallowedApplications. - final UidRange userRange = UidRange.createForUser(userId); + final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); int start = userRange.start; for (int uid : getAppsUids(disallowedApplications, userId)) { if (uid == start) { @@ -1522,7 +1523,7 @@ public class Vpn { if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); } else { // Add all UIDs for the user. - ranges.add(UidRange.createForUser(userId)); + ranges.add(UidRange.createForUser(UserHandle.of(userId))); } } @@ -1531,7 +1532,7 @@ public class Vpn { private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) { // UidRange#createForUser returns the entire range of UIDs available to a macro-user. // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE} - final UidRange userRange = UidRange.createForUser(userId); + final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); final List<UidRange> ranges = new ArrayList<>(); for (UidRange range : existingRanges) { if (userRange.containsRange(range)) { @@ -2528,7 +2529,7 @@ public class Vpn { address /* unused */, address /* unused */, network); - mNms.setInterfaceUp(mTunnelIface.getInterfaceName()); + NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName()); mSession = mIkev2SessionCreator.createIkeSession( mContext, diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index a4e2c7001b27..5b2b3366b117 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -228,8 +228,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { mSidekickInternal = LocalServices.getService(SidekickInternal.class); mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay, mSurfaceControlProxy); - mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken); - mGameContentTypeSupported = SurfaceControl.getGameContentTypeSupport(displayToken); mDisplayDeviceConfig = null; } @@ -250,6 +248,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, dynamicInfo.activeColorMode); changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities); + changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported); + changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported); if (changed) { mHavePendingChanges = true; @@ -522,6 +522,22 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } + private boolean updateAllmSupport(boolean supported) { + if (mAllmSupported == supported) { + return false; + } + mAllmSupported = supported; + return true; + } + + private boolean updateGameContentTypeSupport(boolean supported) { + if (mGameContentTypeSupported == supported) { + return false; + } + mGameContentTypeSupported = supported; + return true; + } + private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes, int modeId) { for (SurfaceControl.DisplayMode mode : supportedModes) { @@ -702,7 +718,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { setDisplayState(Display.STATE_ON); currentState = Display.STATE_ON; } else { - return; // old state and new state is off + if (oldState == Display.STATE_UNKNOWN) { + // There's no guarantee about what the initial state is + // at startup, so we have to set it if previous was UNKNOWN. + setDisplayState(state); + } + return; } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index f6a79ba1abfb..bbe52bcecea2 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -249,7 +249,12 @@ public class InputManagerService extends IInputManager.Stub new ArrayMap<IBinder, LightSession>(); // State for lid switch + // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events + // are delivered in order. For ex, when a new lid switch callback is registered the lock is held + // while the callback is processing the initial lid switch event which guarantees that any + // events that occur at the same time are delivered after the callback has returned. private final Object mLidSwitchLock = new Object(); + @GuardedBy("mLidSwitchLock") private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>(); // State for the currently installed input filter. @@ -403,9 +408,6 @@ public class InputManagerService extends IInputManager.Stub public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER; public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE; - /** Indicates an open state for the lid switch. */ - public static final int SW_STATE_LID_OPEN = 0; - /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; @@ -441,13 +443,18 @@ public class InputManagerService extends IInputManager.Stub } void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) { - boolean lidOpen; synchronized (mLidSwitchLock) { mLidSwitchCallbacks.add(callback); - lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID) - == SW_STATE_LID_OPEN; + + // Skip triggering the initial callback if the system is not yet ready as the switch + // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in + // systemRunning(). + if (mSystemReady) { + boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID) + == KEY_STATE_UP; + callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen); + } } - callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen); } void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) { @@ -495,7 +502,18 @@ public class InputManagerService extends IInputManager.Stub } mNotificationManager = (NotificationManager)mContext.getSystemService( Context.NOTIFICATION_SERVICE); - mSystemReady = true; + + synchronized (mLidSwitchLock) { + mSystemReady = true; + + // Send the initial lid switch state to any callback registered before the system was + // ready. + int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID); + for (int i = 0; i < mLidSwitchCallbacks.size(); i++) { + LidSwitchCallback callback = mLidSwitchCallbacks.get(i); + callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP); + } + } IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -2540,14 +2558,13 @@ public class InputManagerService extends IInputManager.Stub if ((switchMask & SW_LID_BIT) != 0) { final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); - - ArrayList<LidSwitchCallback> callbacksCopy; synchronized (mLidSwitchLock) { - callbacksCopy = new ArrayList<>(mLidSwitchCallbacks); - } - for (int i = 0; i < callbacksCopy.size(); i++) { - LidSwitchCallback callbacks = callbacksCopy.get(i); - callbacks.notifyLidSwitchChanged(whenNanos, lidOpen); + if (mSystemReady) { + for (int i = 0; i < mLidSwitchCallbacks.size(); i++) { + LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i); + callbacks.notifyLidSwitchChanged(whenNanos, lidOpen); + } + } } } diff --git a/services/core/java/com/android/server/input/OWNERS b/services/core/java/com/android/server/input/OWNERS index 0313a40f7270..82c6ee12c7ae 100644 --- a/services/core/java/com/android/server/input/OWNERS +++ b/services/core/java/com/android/server/input/OWNERS @@ -1,2 +1,3 @@ +lzye@google.com michaelwr@google.com svv@google.com diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index fd0b9454cfc1..1bf9da701311 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -496,7 +496,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void startGnssBatch(long periodNanos, ILocationListener listener, String packageName, - String attributionTag, String listenerId) { + @Nullable String attributionTag, String listenerId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); if (mGnssManagerService == null) { @@ -633,7 +633,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Nullable @Override public ICancellationSignal getCurrentLocation(String provider, LocationRequest request, - ILocationCallback consumer, String packageName, String attributionTag, + ILocationCallback consumer, String packageName, @Nullable String attributionTag, String listenerId) { CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, listenerId); @@ -657,7 +657,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void registerLocationListener(String provider, LocationRequest request, ILocationListener listener, String packageName, @Nullable String attributionTag, - @Nullable String listenerId) { + String listenerId) { CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, listenerId); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), @@ -808,7 +808,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public Location getLastLocation(String provider, LastLocationRequest request, - String packageName, String attributionTag) { + String packageName, @Nullable String attributionTag) { CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); @@ -875,9 +875,10 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName, - String attributionTag) { + @Nullable String attributionTag, String listenerId) { if (mGnssManagerService != null) { - mGnssManagerService.registerGnssStatusCallback(listener, packageName, attributionTag); + mGnssManagerService.registerGnssStatusCallback(listener, packageName, attributionTag, + listenerId); } } @@ -890,9 +891,10 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, - String attributionTag) { + @Nullable String attributionTag, String listenerId) { if (mGnssManagerService != null) { - mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag); + mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag, + listenerId); } } @@ -904,11 +906,12 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request, - IGnssMeasurementsListener listener, String packageName, String attributionTag) { + public void addGnssMeasurementsListener(GnssMeasurementRequest request, + IGnssMeasurementsListener listener, String packageName, @Nullable String attributionTag, + String listenerId) { if (mGnssManagerService != null) { mGnssManagerService.addGnssMeasurementsListener(request, listener, packageName, - attributionTag); + attributionTag, listenerId); } } @@ -954,10 +957,10 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener, - String packageName, String attributionTag) { + String packageName, @Nullable String attributionTag, String listenerId) { if (mGnssManagerService != null) { mGnssManagerService.addGnssNavigationMessageListener(listener, packageName, - attributionTag); + attributionTag, listenerId); } } diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index b6695c20bd97..8312c6361835 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -60,7 +60,7 @@ public class GnssManagerService { private static final String ATTRIBUTION_ID = "GnssService"; - private final Context mContext; + final Context mContext; private final GnssNative mGnssNative; private final GnssLocationProvider mGnssLocationProvider; @@ -154,10 +154,11 @@ public class GnssManagerService { * Registers listener for GNSS status changes. */ public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName, - @Nullable String attributionTag) { + @Nullable String attributionTag, String listenerId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, + listenerId); mGnssStatusProvider.addListener(identity, listener); } @@ -172,10 +173,11 @@ public class GnssManagerService { * Registers listener for GNSS NMEA messages. */ public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, - @Nullable String attributionTag) { + @Nullable String attributionTag, String listenerId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, + listenerId); mGnssNmeaProvider.addListener(identity, listener); } @@ -191,12 +193,13 @@ public class GnssManagerService { */ public void addGnssMeasurementsListener(GnssMeasurementRequest request, IGnssMeasurementsListener listener, String packageName, - @Nullable String attributionTag) { + @Nullable String attributionTag, String listenerId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); if (request.isCorrelationVectorOutputsEnabled()) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); } - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, + listenerId); mGnssMeasurementsProvider.addListener(request, identity, listener); } @@ -223,10 +226,11 @@ public class GnssManagerService { * Adds a GNSS navigation message listener. */ public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener, - String packageName, @Nullable String attributionTag) { + String packageName, @Nullable String attributionTag, String listenerId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, + listenerId); mGnssNavigationMessageProvider.addListener(identity, listener); } diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 30ea5556b41c..7e00fd69a148 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -194,7 +194,9 @@ class RebootEscrowManager { } public void reportMetric(boolean success) { - FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success); + // TODO(b/179105110) design error code; and report the true value for other fields. + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1, + -1, 0); } public RebootEscrowEventLog getEventLog() { diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index d95a7254efe1..9c4c5101cb6c 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -425,7 +425,7 @@ public final class NativeTombstoneManager { } } stream.end(token); - + break; case (int) Tombstone.SELINUX_LABEL: selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL); diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index b9e3e0f4450b..0a443f3fd7f9 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -780,7 +780,8 @@ public class PackageDexOptimizer { return getOatDir(codePath).getAbsolutePath(); } - static File getOatDir(File codePath) { + /** Returns the oat dir for the given code path */ + public static File getOatDir(File codePath) { return new File(codePath, OAT_DIR_NAME); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b0037f423563..16966d4de4e6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -369,6 +369,7 @@ import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.Settings.DatabaseVersion; import com.android.server.pm.Settings.VersionInfo; import com.android.server.pm.dex.ArtManagerService; +import com.android.server.pm.dex.ArtUtils; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.PackageDexUsage; @@ -27525,43 +27526,14 @@ public class PackageManagerService extends IPackageManager.Stub } } - private String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) { - if (!AndroidPackageUtils.canHaveOatDir(pkg, - pkgSetting.getPkgState().isUpdatedSystemApp())) { - return null; - } - File codePath = new File(pkg.getPath()); - if (codePath.isDirectory()) { - return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); - } - return null; - } - void deleteOatArtifactsOfPackage(String packageName) { - final String[] instructionSets; - final List<String> codePaths; - final String oatDir; final AndroidPackage pkg; final PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); pkgSetting = mSettings.getPackageLPr(packageName); } - instructionSets = getAppDexInstructionSets( - AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), - AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); - codePaths = AndroidPackageUtils.getAllCodePaths(pkg); - oatDir = getOatDir(pkg, pkgSetting); - - for (String codePath : codePaths) { - for (String isa : instructionSets) { - try { - mInstaller.deleteOdex(codePath, isa, oatDir); - } catch (InstallerException e) { - Log.e(TAG, "Failed deleting oat files for " + codePath, e); - } - } - } + mDexManager.deleteOptimizedFiles(ArtUtils.createArtPackageInfo(pkg, pkgSetting)); } Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f1ffdaf7f111..ec7b451c6ec9 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -40,7 +40,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.IntentFilterVerificationInfo; -import android.content.pm.overlay.OverlayPaths; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageUserState; @@ -72,6 +71,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.os.incremental.IncrementalManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.service.pm.PackageServiceDumpProto; @@ -1028,6 +1028,9 @@ public final class Settings implements Watchable, Snappable { pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath; } pkgSetting.setPath(codePath); + if (IncrementalManager.isIncrementalPath(codePath.getAbsolutePath())) { + pkgSetting.incrementalStates = new IncrementalStates(); + } } // If what we are scanning is a system (and possibly privileged) package, // then make it so, regardless of whether it was previously installed only diff --git a/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java new file mode 100644 index 000000000000..50bf916dceb3 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.dex; + +import java.util.List; + +/** + * Holds package information relevant to ART use cases. + */ +public class ArtPackageInfo { + private final String mPackageName; + private final List<String> mInstructionSets; + private final List<String> mCodePaths; + // TODO: This should be computed on the fly in PackageDexOptimizer / DexManager, but the + // logic is too complicated to do it in a single re-factoring. + private final String mOatDir; + + public ArtPackageInfo( + String packageName, + List<String> instructionSets, + List<String> codePaths, + String oatDir) { + mPackageName = packageName; + mInstructionSets = instructionSets; + mCodePaths = codePaths; + mOatDir = oatDir; + } + + public String getPackageName() { + return mPackageName; + } + + public List<String> getInstructionSets() { + return mInstructionSets; + } + + public List<String> getCodePaths() { + return mCodePaths; + } + + public String getOatDir() { + return mOatDir; + } +} diff --git a/services/core/java/com/android/server/pm/dex/ArtUtils.java b/services/core/java/com/android/server/pm/dex/ArtUtils.java new file mode 100644 index 000000000000..16d7a9a0afd8 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtUtils.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.dex; + +import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; + +import android.annotation.NonNull; + +import com.android.server.pm.PackageDexOptimizer; +import com.android.server.pm.PackageSetting; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; + +import java.io.File; +import java.util.Arrays; + +/** + * Utility class to interface between PM and ART tooling (e.g. DexManager). + */ +public final class ArtUtils { + private ArtUtils() { + } + + /** + * Create the ART-representation of package info. + */ + public static ArtPackageInfo createArtPackageInfo( + AndroidPackage pkg, PackageSetting pkgSetting) { + return new ArtPackageInfo( + pkg.getPackageName(), + Arrays.asList(getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting))), + AndroidPackageUtils.getAllCodePaths(pkg), + getOatDir(pkg, pkgSetting)); + } + + private static String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) { + if (!AndroidPackageUtils.canHaveOatDir(pkg, + pkgSetting.getPkgState().isUpdatedSystemApp())) { + return null; + } + File codePath = new File(pkg.getPath()); + if (codePath.isDirectory()) { + return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); + } + return null; + } + +} diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index cc6d80a2aeec..349561d3f1d1 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -215,7 +215,7 @@ public class DexManager { searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT; if (primaryOrSplit && !isUsedByOtherApps - && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) { + && !isPlatformPackage(searchResult.mOwningPackageName)) { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. @@ -232,15 +232,24 @@ public class DexManager { } String classLoaderContext = mapping.getValue(); + + // Overwrite the class loader context for system server (instead of merging it). + // We expect system server jars to only change contexts in between OTAs and to + // otherwise be stable. + // Instead of implementing a complex clear-context logic post OTA, it is much + // simpler to always override the context for system server. This way, the context + // will always be up to date and we will avoid merging which could lead to the + // the context being marked as variable and thus making dexopt non-optimal. + boolean overwriteCLC = isPlatformPackage(searchResult.mOwningPackageName); + if (classLoaderContext != null && VMRuntime.isValidClassLoaderContext(classLoaderContext)) { // Record dex file usage. If the current usage is a new pattern (e.g. new // secondary, or UsedByOtherApps), record will return true and we trigger an // async write to disk to make sure we don't loose the data in case of a reboot. - if (mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, loaderUserId, loaderIsa, primaryOrSplit, - loadingAppInfo.packageName, classLoaderContext)) { + loadingAppInfo.packageName, classLoaderContext, overwriteCLC)) { mPackageDexUsage.maybeWriteAsync(); } } @@ -474,7 +483,7 @@ public class DexManager { * because they don't need to be compiled).. */ public boolean dexoptSecondaryDex(DexoptOptions options) { - if (PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) { + if (isPlatformPackage(options.getPackageName())) { // We could easily redirect to #dexoptSystemServer in this case. But there should be // no-one calling this method directly for system server. // As such we prefer to abort in this case. @@ -534,7 +543,7 @@ public class DexManager { * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded. */ public int dexoptSystemServer(DexoptOptions options) { - if (!PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) { + if (!isPlatformPackage(options.getPackageName())) { Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:" + options.getPackageName()); return PackageDexOptimizer.DEX_OPT_FAILED; @@ -662,7 +671,7 @@ public class DexManager { // Special handle system server files. // We don't need an installd call because we have permissions to check if the file // exists. - if (PLATFORM_PACKAGE_NAME.equals(packageName)) { + if (isPlatformPackage(packageName)) { if (!Files.exists(Paths.get(dexPath))) { if (DEBUG) { Slog.w(TAG, "A dex file previously loaded by System Server does not exist " @@ -739,7 +748,8 @@ public class DexManager { boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, userId, isa, /*primaryOrSplit*/ false, loadingPackage, - PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT); + PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, + /*overwriteCLC*/ false); update |= newUpdate; } if (update) { @@ -809,7 +819,7 @@ public class DexManager { // Note: We don't have any way to detect which code paths are actually // owned by system server. We can only assume that such paths are on // system partitions. - if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) { + if (isPlatformPackage(loadingAppInfo.packageName)) { if (isSystemServerDexPathSupportedForOdex(dexPath)) { // We record system server dex files as secondary dex files. // The reason is that we only record the class loader context for secondary dex @@ -842,6 +852,11 @@ public class DexManager { return new DexSearchResult(null, DEX_SEARCH_NOT_FOUND); } + /** Returns true if this is the platform package .*/ + private static boolean isPlatformPackage(String packageName) { + return PLATFORM_PACKAGE_NAME.equals(packageName); + } + private static <K,V> V putIfAbsent(Map<K,V> map, K key, V newValue) { V existingValue = map.putIfAbsent(key, newValue); return existingValue == null ? newValue : existingValue; @@ -1000,6 +1015,22 @@ public class DexManager { return isBtmCritical; } + /** + * Deletes all the optimizations files generated by ART. + * @param packageInfo the package information. + */ + public void deleteOptimizedFiles(ArtPackageInfo packageInfo) { + for (String codePath : packageInfo.getCodePaths()) { + for (String isa : packageInfo.getInstructionSets()) { + try { + mInstaller.deleteOdex(codePath, isa, packageInfo.getOatDir()); + } catch (InstallerException e) { + Log.e(TAG, "Failed deleting oat files for " + codePath, e); + } + } + } + } + public static class RegisterDexModuleResult { public RegisterDexModuleResult() { this(false, null); diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java index 10760f52a02b..3d63b75c5da1 100644 --- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java +++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java @@ -111,17 +111,18 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { * @param dexPath the path of the dex files being loaded * @param ownerUserId the user id which runs the code loading the dex files * @param loaderIsa the ISA of the app loading the dex files - * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates * the file is either primary or a split. False indicates the file is secondary dex. * @param loadingPackageName the package performing the load. Recorded only if it is different * than {@param owningPackageName}. + * @param overwriteCLC if true, the class loader context will be overwritten instead of being + * merged * @return true if the dex load constitutes new information, or false if this information * has been seen before. */ /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId, String loaderIsa, boolean primaryOrSplit, - String loadingPackageName, String classLoaderContext) { + String loadingPackageName, String classLoaderContext, boolean overwriteCLC) { if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported"); } @@ -193,7 +194,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } // Merge the information into the existing data. // Returns true if there was an update. - return existingData.merge(newData) || updateLoadingPackages; + return existingData.merge(newData, overwriteCLC) || updateLoadingPackages; } } } @@ -809,14 +810,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { mLoadingPackages = new HashSet<>(other.mLoadingPackages); } - private boolean merge(DexUseInfo dexUseInfo) { + private boolean merge(DexUseInfo dexUseInfo, boolean overwriteCLC) { boolean oldIsUsedByOtherApps = mIsUsedByOtherApps; mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps; boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas); boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages); String oldClassLoaderContext = mClassLoaderContext; - if (isUnsupportedContext(mClassLoaderContext)) { + if (overwriteCLC) { + mClassLoaderContext = dexUseInfo.mClassLoaderContext; + } else if (isUnsupportedContext(mClassLoaderContext)) { mClassLoaderContext = dexUseInfo.mClassLoaderContext; } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { // We detected a context change. diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 71e53d9f1f40..7a936ec29498 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -68,15 +68,10 @@ import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManagerInternal; -import android.app.role.RoleManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PermissionGroupInfoFlags; import android.content.pm.PackageManager.PermissionInfoFlags; @@ -86,7 +81,6 @@ import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.UserInfo; import android.content.pm.parsing.component.ParsedPermission; import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.permission.SplitPermissionInfoParcelable; @@ -401,105 +395,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { new PermissionManagerServiceInternalImpl(); LocalServices.addService(PermissionManagerServiceInternal.class, localService); LocalServices.addService(PermissionManagerInternal.class, localService); - - context.getMainThreadHandler().post(() -> context.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - return; - } - - try { - fixBgMicCamera(context); - } catch (Throwable t) { - // Don't crash the system if this fails for any reason. Any intermediate state - // this can leave the permissions in is okay and in the worst case the state is - // the same as before the user rebooted. - Log.e(LOG_TAG, "Unable to fix background permissions", t); - } - } - - - private void fixBgMicCamera(Context context) { - PackageManager pm = context.getPackageManager(); - for (UserInfo userInfo : context.getSystemService(UserManager.class).getUsers()) { - UserHandle user = userInfo.getUserHandle(); - List<String> assistants = context.getSystemService(RoleManager.class) - .getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, user); - List<PackageInfo> packages = - pm.getInstalledPackagesAsUser(PackageManager.MATCH_SYSTEM_ONLY - | PackageManager.GET_PERMISSIONS, user.getIdentifier()); - for (PackageInfo packageInfo : packages) { - String[] requestedPermissions = packageInfo.requestedPermissions; - if (requestedPermissions == null) { - continue; - } - for (String permName : requestedPermissions) { - String pkg = packageInfo.packageName; - switch (permName) { - case Manifest.permission.BACKGROUND_CAMERA: - removeFromAllowlistsAndRevoke(pm, pkg, permName, user); - break; - case Manifest.permission.RECORD_BACKGROUND_AUDIO: - if (assistants.contains(pkg)) { - removeFromAllowlistsAndRevokeForAssistant(pm, pkg, permName, - user); - } else { - removeFromAllowlistsAndRevoke(pm, pkg, permName, user); - } - break; - } - } - } - } - } - - private void removeFromAllowlistsAndRevoke(PackageManager pm, String pkg, - String permName, UserHandle user) { - if ((pm.getPermissionFlags(permName, pkg, user) - & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) { - Slog.i(LOG_TAG, "removing " + pkg + " " + permName + " from all allowlists"); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_UPGRADE); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_SYSTEM); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_INSTALLER); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_ALLOWLIST_ROLE); - } - if (pm.checkPermission(permName, pkg) == PackageManager.PERMISSION_GRANTED) { - Slog.i(LOG_TAG, "revoking " + pkg + " " + permName); - pm.revokeRuntimePermission(pkg, permName, user); - } - } - - private void removeFromAllowlistsAndRevokeForAssistant(PackageManager pm, String pkg, - String permName, UserHandle user) { - int anyNonRoleExempt = - FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT - | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT - | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; - - if ((pm.getPermissionFlags(permName, pkg, user) & anyNonRoleExempt) != 0) { - Slog.i(LOG_TAG, "removing " + pkg + " " + permName - + " from all allowlists except role"); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_UPGRADE); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_SYSTEM); - pm.removeWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_WHITELIST_INSTALLER); - } - if ((pm.getPermissionFlags(permName, pkg, user) - & FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT) == 0) { - Slog.i(LOG_TAG, "adding " + pkg + " " + permName - + " to role allowlist"); - pm.addWhitelistedRestrictedPermission(pkg, permName, - FLAG_PERMISSION_ALLOWLIST_ROLE); - } - } - }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED))); } @Override diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 9ee072ee7ce5..06748a3aa2d1 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -969,7 +969,7 @@ public class VcnGatewayConnection extends StateMachine { mGatewayStatusCallback.onGatewayConnectionError( mConnectionConfig.getRequiredUnderlyingCapabilities(), VCN_ERROR_CODE_INTERNAL_ERROR, - "java.lang.RuntimeException", + RuntimeException.class.getName(), "Received " + exception.getClass().getSimpleName() + " with message: " @@ -991,11 +991,11 @@ public class VcnGatewayConnection extends StateMachine { } else if (exception instanceof IkeInternalException && exception.getCause() instanceof IOException) { errorCode = VCN_ERROR_CODE_NETWORK_ERROR; - exceptionClass = "java.io.IOException"; + exceptionClass = IOException.class.getName(); exceptionMessage = exception.getCause().getMessage(); } else { errorCode = VCN_ERROR_CODE_INTERNAL_ERROR; - exceptionClass = "java.lang.RuntimeException"; + exceptionClass = RuntimeException.class.getName(); exceptionMessage = "Received " + exception.getClass().getSimpleName() diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index b106657dee99..d5ded97ee0b9 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -788,8 +788,13 @@ public class DisplayRotation { mFixedToUserRotation = fixedToUserRotation; mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation); - mService.updateRotation(true /* alwaysSendConfiguration */, - false /* forceRelayout */); + if (mDisplayContent.mFocusedApp != null) { + // We record the last focused TDA that respects orientation request, check if this + // change may affect it. + mDisplayContent.onLastFocusedTaskDisplayAreaChanged( + mDisplayContent.mFocusedApp.getDisplayArea()); + } + mDisplayContent.updateOrientation(); } @VisibleForTesting diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 4551d49d9e58..f054e7c73015 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -86,7 +86,7 @@ static int compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType) int pidfd = syscall(__NR_pidfd_open, pid, 0); err = -errno; - if (err < 0) { + if (pidfd < 0) { // Skip compaction if failed to open pidfd with any error return err; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 7260732bbcb6..6857a685fe17 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -333,6 +333,7 @@ import com.google.android.collect.Sets; import org.xmlpull.v1.XmlPullParserException; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -340,6 +341,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.text.DateFormat; import java.time.LocalDate; import java.util.ArrayList; @@ -5622,7 +5626,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Get attestation flags, if any. final int[] attestationUtilsFlags = translateIdAttestationFlags(idAttestationFlags); final boolean deviceIdAttestationRequired = attestationUtilsFlags != null; - final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec(); + KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec(); final String alias = keySpec.getKeystoreAlias(); Preconditions.checkStringNotEmpty(alias, "Empty alias provided"); @@ -5643,6 +5647,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp))); } + if (TextUtils.isEmpty(alias)) { + throw new IllegalArgumentException("Empty alias provided."); + } // As the caller will be granted access to the key, ensure no UID was specified, as // it will not have the desired effect. if (keySpec.getUid() != KeyStore.UID_SELF) { @@ -5651,19 +5658,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } + if (deviceIdAttestationRequired) { + if (keySpec.getAttestationChallenge() == null) { + throw new IllegalArgumentException( + "Requested Device ID attestation but challenge is empty."); + } + KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(keySpec); + specBuilder.setAttestationIds(attestationUtilsFlags); + specBuilder.setDevicePropertiesAttestationIncluded(true); + keySpec = specBuilder.build(); + } + + final UserHandle userHandle = mInjector.binderGetCallingUserHandle(); final long id = mInjector.binderClearCallingIdentity(); try { try (KeyChainConnection keyChainConnection = - KeyChain.bindAsUser(mContext, caller.getUserHandle())) { + KeyChain.bindAsUser(mContext, userHandle)) { IKeyChainService keyChain = keyChainConnection.getService(); - // Copy the provided keySpec, excluding the attestation challenge, which will be - // used later for requesting key attestation record. - final KeyGenParameterSpec noAttestationSpec = new KeyGenParameterSpec.Builder( - keySpec).setAttestationChallenge(null).build(); - final int generationResult = keyChain.generateKeyPair(algorithm, - new ParcelableKeyGenParameterSpec(noAttestationSpec)); + new ParcelableKeyGenParameterSpec(keySpec)); if (generationResult != KeyChain.KEY_GEN_SUCCESS) { Log.e(LOG_TAG, String.format( "KeyChain failed to generate a keypair, error %d.", generationResult)); @@ -5672,6 +5686,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new ServiceSpecificException( DevicePolicyManager.KEY_GEN_STRONGBOX_UNAVAILABLE, String.format("KeyChain error: %d", generationResult)); + case KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS: + throw new UnsupportedOperationException( + "Device does not support Device ID attestation."); default: logGenerateKeyPairFailure(caller, isCredentialManagementApp); return false; @@ -5685,23 +5702,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // that UID. keyChain.setGrant(caller.getUid(), alias, true); - final byte[] attestationChallenge = keySpec.getAttestationChallenge(); - if (attestationChallenge != null) { - final int attestationResult = keyChain.attestKey( - alias, attestationChallenge, attestationUtilsFlags, attestationChain); - if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) { - Log.e(LOG_TAG, String.format( - "Attestation for %s failed (rc=%d), deleting key.", - alias, attestationResult)); - keyChain.removeKeyPair(alias); - if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) { - throw new UnsupportedOperationException( - "Device does not support Device ID attestation."); + try { + final List<byte[]> encodedCerts = new ArrayList(); + final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + final byte[] certChainBytes = keyChain.getCaCertificates(alias); + encodedCerts.add(keyChain.getCertificate(alias)); + if (certChainBytes != null) { + final Collection<X509Certificate> certs = + (Collection<X509Certificate>) certFactory.generateCertificates( + new ByteArrayInputStream(certChainBytes)); + for (X509Certificate cert : certs) { + encodedCerts.add(cert.getEncoded()); } - logGenerateKeyPairFailure(caller, isCredentialManagementApp); - return false; } + + attestationChain.shallowCopyFrom(new KeymasterCertificateChain(encodedCerts)); + } catch (CertificateException e) { + logGenerateKeyPairFailure(caller, isCredentialManagementApp); + Log.e(LOG_TAG, "While retrieving certificate chain.", e); + return false; } + DevicePolicyEventLogger .createEvent(DevicePolicyEnums.GENERATE_KEY_PAIR) .setAdmin(caller.getPackageName()) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index dd2dd8150165..d50db91acc99 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -104,7 +104,6 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.ILockSettings; import com.android.server.am.ActivityManagerService; import com.android.server.appbinding.AppBindingService; -import com.android.server.apphibernation.AppHibernationService; import com.android.server.attention.AttentionManagerService; import com.android.server.audio.AudioService; import com.android.server.biometrics.AuthService; @@ -1785,7 +1784,7 @@ public final class SystemServer implements Dumpable { t.traceBegin("StartIpSecService"); try { - ipSecService = IpSecService.create(context, networkManagement); + ipSecService = IpSecService.create(context); ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService); } catch (Throwable e) { reportWtf("starting IpSec Service", e); @@ -2150,11 +2149,9 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS); t.traceEnd(); - if (AppHibernationService.isAppHibernationEnabled()) { - t.traceBegin("StartAppHibernationService"); - mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS); - t.traceEnd(); - } + t.traceBegin("StartAppHibernationService"); + mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS); + t.traceEnd(); if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) { t.traceBegin("StartGestureLauncher"); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java index 56d30ccdf59f..20a58426f1eb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java @@ -139,7 +139,8 @@ public final class CachedAppOptimizerTest { app.info.uid = packageUid; // Exact value does not mater, it can be any state for which compaction is allowed. app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); - app.mState.setSetAdj(905); + app.mState.setSetAdj(899); + app.mState.setCurAdj(940); return app; } @@ -164,8 +165,6 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); - assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( - CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleBFGS).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo( @@ -176,6 +175,11 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo( CachedAppOptimizer.DEFAULT_USE_FREEZER); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ); + Set<Integer> expected = new HashSet<>(); for (String s : TextUtils.split( @@ -231,6 +235,14 @@ public final class CachedAppOptimizerTest { Long.toString( CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, + Long.toString( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, + Long.toString( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false); assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo( CachedAppOptimizer.DEFAULT_USE_FREEZER); @@ -261,6 +273,12 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1); + assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 10); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10); assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo( @@ -437,7 +455,7 @@ public final class CachedAppOptimizerTest { mCachedAppOptimizerUnderTest.init(); // When we override new reasonable throttle values after init... - mCountDown = new CountDownLatch(6); + mCountDown = new CountDownLatch(8); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_THROTTLE_1, Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1), false); @@ -456,7 +474,13 @@ public final class CachedAppOptimizerTest { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_THROTTLE_6, Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1), false); - assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, + Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, + Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1), false); + assertThat(mCountDown.await(7, TimeUnit.SECONDS)).isTrue(); // Then those flags values are reflected in the compactor. assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo( @@ -471,6 +495,10 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ + 1); + assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo( + CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 1); } @Test @@ -902,7 +930,6 @@ public final class CachedAppOptimizerTest { valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get( pid).getRssAfterCompaction(); assertThat(valuesAfter).isEqualTo(rssAfter3); - } @Test @@ -954,6 +981,54 @@ public final class CachedAppOptimizerTest { assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter); } + @Test + public void processWithOomAdjTooSmall_notFullCompacted() throws Exception { + // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set Min and + // Max OOM_Adj throttles. + mCachedAppOptimizerUnderTest.init(); + setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true); + setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true); + setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true); + initActivityManagerService(); + + // Simulate RSS memory for which compaction should occur. + long[] rssBefore = + new long[]{/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000, + /*Swap*/ 10000}; + long[] rssAfter = + new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/5000}; + // Process that passes properties. + int pid = 1; + ProcessRecord processRecord = + makeProcessRecord(pid, 2, 3, "p1", "app1"); + mProcessDependencies.setRss(rssBefore); + mProcessDependencies.setRssAfterCompaction(rssAfter); + + // Compaction should occur if (setAdj < min for process || setAdj > max for process) && + // (MIN < curAdj < MAX) + // GIVEN OomAdj score below threshold. + processRecord.mState.setSetAdj(899); + processRecord.mState.setCurAdj(970); + // WHEN we try to run compaction + mCachedAppOptimizerUnderTest.compactAppFull(processRecord); + waitForHandler(); + // THEN process IS NOT compacted. + assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull(); + + // GIVEN (setAdj < MIN || setAdj > MAX) && (MIN < curAdj < MAX) + processRecord.mState.setSetAdj(910); + processRecord.mState.setCurAdj(930); + // WHEN we try to run compaction + mCachedAppOptimizerUnderTest.compactAppFull(processRecord); + waitForHandler(); + // THEN process IS compacted. + assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull(); + long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats + .get(pid) + .getRssAfterCompaction(); + assertThat(valuesAfter).isEqualTo(rssAfter); + } + private void setFlag(String key, String value, boolean defaultValue) throws Exception { mCountDown = new CountDownLatch(1); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index d6d1c466c92f..728b97cc3968 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -437,6 +437,74 @@ public class LocalDisplayAdapterTest { } @Test + public void testAfterDisplayChange_AllmSupportIsUpdated() throws Exception { + FakeDisplay display = new FakeDisplay(PORT_A); + display.dynamicInfo.autoLowLatencyModeSupported = true; + setUpDisplay(display); + updateAvailableDisplays(); + mAdapter.registerLocked(); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays).isEmpty(); + + DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0) + .getDisplayDeviceInfoLocked(); + + assertThat(displayDeviceInfo.allmSupported).isTrue(); + + // Change the display + display.dynamicInfo.autoLowLatencyModeSupported = false; + setUpDisplay(display); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertTrue(mListener.traversalRequested); + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays.size()).isEqualTo(1); + + DisplayDevice displayDevice = mListener.changedDisplays.get(0); + displayDevice.applyPendingDisplayDeviceInfoChangesLocked(); + displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); + + assertThat(displayDeviceInfo.allmSupported).isFalse(); + } + + @Test + public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception { + FakeDisplay display = new FakeDisplay(PORT_A); + display.dynamicInfo.gameContentTypeSupported = true; + setUpDisplay(display); + updateAvailableDisplays(); + mAdapter.registerLocked(); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays).isEmpty(); + + DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0) + .getDisplayDeviceInfoLocked(); + + assertThat(displayDeviceInfo.gameContentTypeSupported).isTrue(); + + // Change the display + display.dynamicInfo.gameContentTypeSupported = false; + setUpDisplay(display); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertTrue(mListener.traversalRequested); + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays.size()).isEqualTo(1); + + DisplayDevice displayDevice = mListener.changedDisplays.get(0); + displayDevice.applyPendingDisplayDeviceInfoChangesLocked(); + displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); + + assertThat(displayDeviceInfo.gameContentTypeSupported).isFalse(); + } + + @Test public void testAfterDisplayChange_ColorModesAreUpdated() throws Exception { FakeDisplay display = new FakeDisplay(PORT_A); final int[] initialColorModes = new int[]{Display.COLOR_MODE_BT709}; diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java index 1328b91d03f9..07f67327b2bf 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -110,6 +110,8 @@ public final class AppHibernationServiceTest { UserInfo userInfo = addUser(USER_ID_1); mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo)); doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1); + + mAppHibernationService.mIsServiceEnabled = true; } @Test 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 new file mode 100644 index 000000000000..4308885faaad --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -0,0 +1,124 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +public class AppSearchStatsTest { + static final String TEST_PACKAGE_NAME = "com.google.test"; + static final String TEST_DATA_BASE = "testDataBase"; + static final int TEST_STATUS_CODE = 2; + static final int TEST_TOTAL_LATENCY_MILLIS = 20; + + @Test + public void testAppSearchStats_GeneralStats() { + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + + assertThat(gStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(gStats.getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(gStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(gStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + } + + @Test + public void testAppSearchStats_CallStats() { + final int estimatedBinderLatencyMillis = 1; + final int numOperationsSucceeded = 2; + final int numOperationsFailed = 3; + + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + final @CallStats.CallType int callType = CallStats.CALL_TYPE_PUT_DOCUMENTS; + final CallStats cStats = + new CallStats.Builder(gStats) + .setCallType(callType) + .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis) + .setNumOperationsSucceeded(numOperationsSucceeded) + .setNumOperationsFailed(numOperationsFailed) + .build(); + + assertThat(cStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(cStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(cStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(cStats.getGeneralStats().getTotalLatencyMillis()) + .isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(cStats.getEstimatedBinderLatencyMillis()) + .isEqualTo(estimatedBinderLatencyMillis); + assertThat(cStats.getCallType()).isEqualTo(callType); + assertThat(cStats.getNumOperationsSucceeded()).isEqualTo(numOperationsSucceeded); + assertThat(cStats.getNumOperationsFailed()).isEqualTo(numOperationsFailed); + } + + @Test + public void testAppSearchStats_PutDocumentStats() { + final int generateDocumentProtoLatencyMillis = 1; + final int rewriteDocumentTypesLatencyMillis = 2; + final int nativeLatencyMillis = 3; + final int nativeDocumentStoreLatencyMillis = 4; + final int nativeIndexLatencyMillis = 5; + final int nativeIndexMergeLatencyMillis = 6; + final int nativeDocumentSize = 7; + final int nativeNumTokensIndexed = 8; + final int nativeNumTokensClipped = 9; + + final GeneralStats gStats = + new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .build(); + final PutDocumentStats pStats = + new PutDocumentStats.Builder(gStats) + .setGenerateDocumentProtoLatencyMillis(generateDocumentProtoLatencyMillis) + .setRewriteDocumentTypesLatencyMillis(rewriteDocumentTypesLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setNativeDocumentStoreLatencyMillis(nativeDocumentStoreLatencyMillis) + .setNativeIndexLatencyMillis(nativeIndexLatencyMillis) + .setNativeIndexMergeLatencyMillis(nativeIndexMergeLatencyMillis) + .setNativeDocumentSizeBytes(nativeDocumentSize) + .setNativeNumTokensIndexed(nativeNumTokensIndexed) + .setNativeNumTokensClipped(nativeNumTokensClipped) + .build(); + + assertThat(pStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(pStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(pStats.getGeneralStats().getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(pStats.getGeneralStats().getTotalLatencyMillis()) + .isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(pStats.getGenerateDocumentProtoLatencyMillis()) + .isEqualTo(generateDocumentProtoLatencyMillis); + assertThat(pStats.getRewriteDocumentTypesLatencyMillis()) + .isEqualTo(rewriteDocumentTypesLatencyMillis); + assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(pStats.getNativeDocumentStoreLatencyMillis()) + .isEqualTo(nativeDocumentStoreLatencyMillis); + assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis); + assertThat(pStats.getNativeIndexMergeLatencyMillis()) + .isEqualTo(nativeIndexMergeLatencyMillis); + assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize); + assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed); + assertThat(pStats.getNativeNumTokensClipped()).isEqualTo(nativeNumTokensClipped); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index ff43da6370e8..ee0a16a70265 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -86,6 +86,7 @@ public class DexManagerTests { private TestData mBarUser0DelegateLastClassLoader; private TestData mSystemServerJar; + private TestData mSystemServerJarUpdatedContext; private TestData mSystemServerJarInvalid; private int mUser0; @@ -113,6 +114,8 @@ public class DexManagerTests { mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); + mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0, + DELEGATE_LAST_CLASS_LOADER_NAME); mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock); @@ -522,6 +525,24 @@ public class DexManagerTests { } @Test + public void testSystemServerOverwritesContext() { + // Record bar secondaries with the default PathClassLoader. + List<String> secondaries = mSystemServerJar.getSecondaryDexPaths(); + + notifyDexLoad(mSystemServerJar, secondaries, mUser0); + PackageUseInfo pui = getPackageUseInfo(mSystemServerJar); + assertSecondaryUse(mSystemServerJar, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); + + // Record bar secondaries again with a different class loader. This will change the context. + notifyDexLoad(mSystemServerJarUpdatedContext, secondaries, mUser0); + + pui = getPackageUseInfo(mSystemServerJar); + // We expect that all the contexts to be updated according to the last notify. + assertSecondaryUse(mSystemServerJarUpdatedContext, pui, secondaries, + /*isUsedByOtherApps*/false, mUser0); + } + + @Test public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() { List<String> secondaries = mBarUser0.getSecondaryDexPaths(); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS new file mode 100644 index 000000000000..66ef75d6c823 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/pm/dex/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java index adf4551e79a8..3450710f60a0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java @@ -451,7 +451,7 @@ public class PackageDexUsageTests { "PCL[new_context.dex]"); assertTrue(record(fooSecondary1User0NewContext)); - // Not check that the context was switch to variable. + // Now check that the context was switch to variable. TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext( PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT); @@ -461,6 +461,22 @@ public class PackageDexUsageTests { } @Test + public void testRecordClassLoaderContextOverwritten() { + // Record a secondary dex file. + assertTrue(record(mFooSecondary1User0)); + // Now update its context. + TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext( + "PCL[new_context.dex]", true); + assertTrue(record(fooSecondary1User0NewContext)); + + // Now check that the context was overwritten. + TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext( + "PCL[new_context.dex]", true); + + assertPackageDexUsage(null, expectedContext); + } + + @Test public void testDexUsageClassLoaderContext() { final boolean isUsedByOtherApps = false; final int userId = 0; @@ -642,8 +658,9 @@ public class PackageDexUsageTests { private boolean record(TestData testData) { return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile, - testData.mOwnerUserId, testData.mLoaderIsa, - testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext); + testData.mOwnerUserId, testData.mLoaderIsa, + testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext, + testData.mOverwriteCLC); } private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) { @@ -651,7 +668,8 @@ public class PackageDexUsageTests { for (String user : users) { result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile, testData.mOwnerUserId, testData.mLoaderIsa, - testData.mPrimaryOrSplit, user, testData.mClassLoaderContext); + testData.mPrimaryOrSplit, user, testData.mClassLoaderContext, + testData.mOverwriteCLC); } return result; } @@ -682,15 +700,16 @@ public class PackageDexUsageTests { private final boolean mPrimaryOrSplit; private final String mUsedBy; private final String mClassLoaderContext; + private final boolean mOverwriteCLC; private TestData(String packageName, String dexFile, int ownerUserId, String loaderIsa, boolean primaryOrSplit, String usedBy) { this(packageName, dexFile, ownerUserId, loaderIsa, primaryOrSplit, - usedBy, "PCL[" + dexFile + "]"); + usedBy, "PCL[" + dexFile + "]", false); } private TestData(String packageName, String dexFile, int ownerUserId, String loaderIsa, boolean primaryOrSplit, String usedBy, - String classLoaderContext) { + String classLoaderContext, boolean overwriteCLC) { mPackageName = packageName; mDexFile = dexFile; mOwnerUserId = ownerUserId; @@ -698,16 +717,21 @@ public class PackageDexUsageTests { mPrimaryOrSplit = primaryOrSplit; mUsedBy = usedBy; mClassLoaderContext = classLoaderContext; + mOverwriteCLC = overwriteCLC; } private TestData updateClassLoaderContext(String newContext) { + return updateClassLoaderContext(newContext, mOverwriteCLC); + } + + private TestData updateClassLoaderContext(String newContext, boolean overwriteCLC) { return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, - mPrimaryOrSplit, mUsedBy, newContext); + mPrimaryOrSplit, mUsedBy, newContext, overwriteCLC); } private TestData updateUsedBy(String newUsedBy) { return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, - mPrimaryOrSplit, newUsedBy, mClassLoaderContext); + mPrimaryOrSplit, newUsedBy, mClassLoaderContext, mOverwriteCLC); } private boolean isUsedByOtherApps() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index aa1110cd55a7..488e629f5790 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2288,7 +2288,7 @@ public class ActivityRecordTests extends WindowTestsBase { IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); reset(task); activity.reportDescendantOrientationChangeIfNeeded(); - verify(task).onConfigurationChanged(any(Configuration.class)); + verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class)); } @Test 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 58169bb1e073..dc702e6bc572 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -32,6 +32,7 @@ import static android.view.DisplayCutout.fromBoundingRect; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_90; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; @@ -121,6 +122,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; +import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Test; @@ -955,16 +957,14 @@ public class DisplayContentTests extends WindowTestsBase { IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); final int newOrientation = getRotatedOrientation(dc); - final Task stack = new TaskBuilder(mSupervisor) + final Task task = new TaskBuilder(mSupervisor) .setDisplay(dc).setCreateActivity(true).build(); - final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity(); + final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity(); + dc.setFocusedApp(activity); activity.setRequestedOrientation(newOrientation); - final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_PORTRAIT - : Configuration.ORIENTATION_LANDSCAPE; - assertEquals(expectedOrientation, dc.getConfiguration().orientation); + assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1); } @Test @@ -972,17 +972,42 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); + dc.getDisplayRotation().setUserRotation( + WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_180); final int newOrientation = getRotatedOrientation(dc); - final Task stack = new TaskBuilder(mSupervisor) + final Task task = new TaskBuilder(mSupervisor) .setDisplay(dc).setCreateActivity(true).build(); - final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity(); + final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity(); + dc.setFocusedApp(activity); activity.setRequestedOrientation(newOrientation); verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity), anyBoolean(), same(null)); - assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation()); + assertEquals(ROTATION_180, dc.getRotation()); + } + + @Test + public void testFixedToUserRotationChanged() { + final DisplayContent dc = createNewDisplay(); + dc.getDisplayRotation().setFixedToUserRotation( + IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); + dc.getDisplayRotation().setUserRotation( + WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0); + final int newOrientation = getRotatedOrientation(dc); + + final Task task = new TaskBuilder(mSupervisor) + .setDisplay(dc).setCreateActivity(true).build(); + final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity(); + dc.setFocusedApp(activity); + + activity.setRequestedOrientation(newOrientation); + + dc.getDisplayRotation().setFixedToUserRotation( + IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); + + assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1); } @Test diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index c6757fba4d53..4ae11b8458cb 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -111,6 +111,7 @@ public class Annotation { public @interface NetworkType { } + // TODO(b/180542000): remove and replace references with @ApnSetting.ApnType @IntDef(flag = true, prefix = {"TYPE_"}, value = { ApnSetting.TYPE_DEFAULT, ApnSetting.TYPE_MMS, @@ -124,6 +125,7 @@ public class Annotation { ApnSetting.TYPE_EMERGENCY, ApnSetting.TYPE_MCX, ApnSetting.TYPE_XCAP, + // ApnSetting.TYPE_ENTERPRISE }) @Retention(RetentionPolicy.SOURCE) public @interface ApnType { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 8c68d856d896..3d43d031868d 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -5321,7 +5321,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY, new String[0]); sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] { - "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", + "default:0", "enterprise:1", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3" }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 99a77ae5d133..c8ed82cd2a3f 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -917,6 +917,10 @@ public final class DataFailCause { public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB; /** Data call fail due to the slice not being allowed for the data call. */ public static final int SLICE_REJECTED = 0x8CC; + /** No matching rule available for the request, and match-all rule is not allowed for it. */ + public static final int MATCH_ALL_RULE_NOT_ALLOWED = 0x8CD; + /** If connection failed for all matching URSP rules. */ + public static final int ALL_MATCHING_RULES_FAILED = 0x8CE; //IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2). diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index d58fa912dce2..b503733f8de9 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -28,8 +28,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.provider.Telephony; import android.provider.Telephony.Carriers; -import android.telephony.Annotation; -import android.telephony.Annotation.ApnType; import android.telephony.Annotation.NetworkType; import android.telephony.ServiceState; import android.telephony.TelephonyManager; @@ -116,6 +114,31 @@ public class ApnSetting implements Parcelable { public static final int TYPE_MCX = ApnTypes.MCX; /** APN type for XCAP. */ public static final int TYPE_XCAP = ApnTypes.XCAP; + /** + * APN type for ENTERPRISE. + * @hide + */ + public static final int TYPE_ENTERPRISE = TYPE_XCAP << 1; + + /** @hide */ + @IntDef(flag = true, prefix = {"TYPE_"}, value = { + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY, + TYPE_MCX, + TYPE_XCAP, + TYPE_ENTERPRISE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ApnType { + } // Possible values for authentication types. /** No authentication type. */ @@ -151,6 +174,7 @@ public class ApnSetting implements Parcelable { TYPE_MMS_STRING, TYPE_SUPL_STRING, TYPE_XCAP_STRING, + TYPE_ENTERPRISE_STRING, }, prefix = "TYPE_", suffix = "_STRING") @Retention(RetentionPolicy.SOURCE) public @interface ApnTypeString {} @@ -291,6 +315,12 @@ public class ApnSetting implements Parcelable { @SystemApi public static final String TYPE_XCAP_STRING = "xcap"; + /** + * APN type for ENTERPRISE traffic. + * @hide + */ + public static final String TYPE_ENTERPRISE_STRING = "enterprise"; + /** @hide */ @IntDef(prefix = { "AUTH_TYPE_" }, value = { @@ -370,6 +400,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_STRING_MAP.put(TYPE_EMERGENCY_STRING, TYPE_EMERGENCY); APN_TYPE_STRING_MAP.put(TYPE_MCX_STRING, TYPE_MCX); APN_TYPE_STRING_MAP.put(TYPE_XCAP_STRING, TYPE_XCAP); + APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE); APN_TYPE_INT_MAP = new ArrayMap<>(); APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING); @@ -384,6 +415,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, TYPE_EMERGENCY_STRING); APN_TYPE_INT_MAP.put(TYPE_MCX, TYPE_MCX_STRING); APN_TYPE_INT_MAP.put(TYPE_XCAP, TYPE_XCAP_STRING); + APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING); PROTOCOL_STRING_MAP = new ArrayMap<>(); PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP); @@ -1490,7 +1522,7 @@ public class ApnSetting implements Parcelable { * @hide */ @SystemApi - public static @NonNull @ApnTypeString String getApnTypeString(@Annotation.ApnType int apnType) { + public static @NonNull @ApnTypeString String getApnTypeString(@ApnType int apnType) { if (apnType == TYPE_ALL) { return "*"; } @@ -1503,7 +1535,7 @@ public class ApnSetting implements Parcelable { * when provided with an invalid int for compatibility purposes. * @hide */ - public static @NonNull String getApnTypeStringInternal(@Annotation.ApnType int apnType) { + public static @NonNull String getApnTypeStringInternal(@ApnType int apnType) { String result = getApnTypeString(apnType); return TextUtils.isEmpty(result) ? "Unknown" : result; } @@ -1517,7 +1549,7 @@ public class ApnSetting implements Parcelable { * @hide */ @SystemApi - public static @Annotation.ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) { + public static @ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) { return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(), 0); } @@ -2162,7 +2194,7 @@ public class ApnSetting implements Parcelable { public ApnSetting build() { if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX - | TYPE_XCAP)) == 0 + | TYPE_XCAP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { return null; } diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index bd4bf0740ca1..a76422977cb6 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -138,6 +138,7 @@ public final class DataCallResponse implements Parcelable { private final Qos mDefaultQos; private final List<QosBearerSession> mQosBearerSessions; private final SliceInfo mSliceInfo; + private final List<TrafficDescriptor> mTrafficDescriptors; /** * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error. @@ -189,6 +190,7 @@ public final class DataCallResponse implements Parcelable { mDefaultQos = null; mQosBearerSessions = new ArrayList<>(); mSliceInfo = null; + mTrafficDescriptors = new ArrayList<>(); } private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id, @@ -198,7 +200,7 @@ public final class DataCallResponse implements Parcelable { @Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6, @HandoverFailureMode int handoverFailureMode, int pduSessionId, @Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions, - @Nullable SliceInfo sliceInfo) { + @Nullable SliceInfo sliceInfo, @Nullable List<TrafficDescriptor> trafficDescriptors) { mCause = cause; mSuggestedRetryTime = suggestedRetryTime; mId = id; @@ -219,8 +221,11 @@ public final class DataCallResponse implements Parcelable { mHandoverFailureMode = handoverFailureMode; mPduSessionId = pduSessionId; mDefaultQos = defaultQos; - mQosBearerSessions = qosBearerSessions; + mQosBearerSessions = (qosBearerSessions == null) + ? new ArrayList<>() : new ArrayList<>(qosBearerSessions); mSliceInfo = sliceInfo; + mTrafficDescriptors = (trafficDescriptors == null) + ? new ArrayList<>() : new ArrayList<>(trafficDescriptors); } /** @hide */ @@ -249,6 +254,8 @@ public final class DataCallResponse implements Parcelable { mQosBearerSessions = new ArrayList<>(); source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader()); mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader()); + mTrafficDescriptors = new ArrayList<>(); + source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader()); } /** @@ -381,7 +388,6 @@ public final class DataCallResponse implements Parcelable { * * @hide */ - @Nullable public Qos getDefaultQos() { return mDefaultQos; @@ -406,6 +412,14 @@ public final class DataCallResponse implements Parcelable { return mSliceInfo; } + /** + * @return The traffic descriptors related to this data connection. + */ + @NonNull + public List<TrafficDescriptor> getTrafficDescriptors() { + return mTrafficDescriptors; + } + @NonNull @Override public String toString() { @@ -429,6 +443,7 @@ public final class DataCallResponse implements Parcelable { .append(" defaultQos=").append(mDefaultQos) .append(" qosBearerSessions=").append(mQosBearerSessions) .append(" sliceInfo=").append(mSliceInfo) + .append(" trafficDescriptors=").append(mTrafficDescriptors) .append("}"); return sb.toString(); } @@ -443,15 +458,22 @@ public final class DataCallResponse implements Parcelable { DataCallResponse other = (DataCallResponse) o; - final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null) ? - mDefaultQos == other.mDefaultQos : - mDefaultQos.equals(other.mDefaultQos); + final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null) + ? mDefaultQos == other.mDefaultQos + : mDefaultQos.equals(other.mDefaultQos); - final boolean isQosBearerSessionsSame = (mQosBearerSessions == null || mQosBearerSessions == null) ? - mQosBearerSessions == other.mQosBearerSessions : - mQosBearerSessions.size() == other.mQosBearerSessions.size() + final boolean isQosBearerSessionsSame = + (mQosBearerSessions == null || other.mQosBearerSessions == null) + ? mQosBearerSessions == other.mQosBearerSessions + : mQosBearerSessions.size() == other.mQosBearerSessions.size() && mQosBearerSessions.containsAll(other.mQosBearerSessions); + final boolean isTrafficDescriptorsSame = + (mTrafficDescriptors == null || other.mTrafficDescriptors == null) + ? mTrafficDescriptors == other.mTrafficDescriptors + : mTrafficDescriptors.size() == other.mTrafficDescriptors.size() + && mTrafficDescriptors.containsAll(other.mTrafficDescriptors); + return mCause == other.mCause && mSuggestedRetryTime == other.mSuggestedRetryTime && mId == other.mId @@ -473,7 +495,8 @@ public final class DataCallResponse implements Parcelable { && mPduSessionId == other.mPduSessionId && isQosSame && isQosBearerSessionsSame - && Objects.equals(mSliceInfo, other.mSliceInfo); + && Objects.equals(mSliceInfo, other.mSliceInfo) + && isTrafficDescriptorsSame; } @Override @@ -481,7 +504,7 @@ public final class DataCallResponse implements Parcelable { return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos, - mQosBearerSessions, mSliceInfo); + mQosBearerSessions, mSliceInfo, mTrafficDescriptors); } @Override @@ -517,6 +540,7 @@ public final class DataCallResponse implements Parcelable { } dest.writeList(mQosBearerSessions); dest.writeParcelable(mSliceInfo, flags); + dest.writeList(mTrafficDescriptors); } public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR = @@ -602,6 +626,8 @@ public final class DataCallResponse implements Parcelable { private SliceInfo mSliceInfo; + private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>(); + /** * Default constructor for Builder. */ @@ -841,6 +867,24 @@ public final class DataCallResponse implements Parcelable { } /** + * The traffic descriptors for this data connection, as defined in 3GPP TS 24.526 + * Section 5.2. They are used for URSP traffic matching as described in 3GPP TS 24.526 + * Section 4.2.2. They includes an optional DNN, which, if present, must be used for traffic + * matching; it does not specify the end point to be used for the data call. The end point + * is specified by {@link DataProfile}, which must be used as the end point if one is not + * specified through URSP rules. + * + * @param trafficDescriptors the traffic descriptors for the data call. + * + * @return The same instance of the builder. + */ + public @NonNull Builder setTrafficDescriptors( + @NonNull List<TrafficDescriptor> trafficDescriptors) { + mTrafficDescriptors = trafficDescriptors; + return this; + } + + /** * Build the DataCallResponse. * * @return the DataCallResponse object. @@ -849,7 +893,7 @@ public final class DataCallResponse implements Parcelable { return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, - mDefaultQos, mQosBearerSessions, mSliceInfo); + mDefaultQos, mQosBearerSessions, mSliceInfo, mTrafficDescriptors); } } } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 484c318c1ac0..f5f29c65b7cd 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -200,6 +200,17 @@ public abstract class DataService extends Service { * handover is occurring from EPDG to 5G. If the slice passed is rejected, then * {@link DataCallResponse#getCause()} is * {@link android.telephony.DataFailCause#SLICE_REJECTED}. + * @param trafficDescriptor {@link TrafficDescriptor} for which data connection needs to be + * established. It is used for URSP traffic matching as described in 3GPP TS 24.526 + * Section 4.2.2. It includes an optional DNN which, if present, must be used for + * traffic matching; it does not specify the end point to be used for the data call. + * @param matchAllRuleAllowed Indicates if using default match-all URSP rule for this + * request is allowed. If false, this request must not use the match-all URSP rule + * and if a non-match-all rule is not found (or if URSP rules are not available) then + * {@link DataCallResponse#getCause()} is + * {@link android.telephony.DataFailCause#MATCH_ALL_RULE_NOT_ALLOWED}. This is needed + * as some requests need to have a hard failure if the intention cannot be met, + * for example, a zero-rating slice. * @param callback The result callback for this request. */ public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile, @@ -207,6 +218,7 @@ public abstract class DataService extends Service { @SetupDataReason int reason, @Nullable LinkProperties linkProperties, @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo, + @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, @NonNull DataServiceCallback callback) { /* Call the old version since the new version isn't supported */ setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, @@ -403,10 +415,13 @@ public abstract class DataService extends Service { public final LinkProperties linkProperties; public final int pduSessionId; public final SliceInfo sliceInfo; + public final TrafficDescriptor trafficDescriptor; + public final boolean matchAllRuleAllowed; public final IDataServiceCallback callback; SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, - int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) { + boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, + SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, + boolean matchAllRuleAllowed, IDataServiceCallback callback) { this.accessNetworkType = accessNetworkType; this.dataProfile = dataProfile; this.isRoaming = isRoaming; @@ -415,6 +430,8 @@ public abstract class DataService extends Service { this.reason = reason; this.pduSessionId = pduSessionId; this.sliceInfo = sliceInfo; + this.trafficDescriptor = trafficDescriptor; + this.matchAllRuleAllowed = matchAllRuleAllowed; this.callback = callback; } } @@ -525,7 +542,8 @@ public abstract class DataService extends Service { setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming, setupDataCallRequest.allowRoaming, setupDataCallRequest.reason, setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId, - setupDataCallRequest.sliceInfo, + setupDataCallRequest.sliceInfo, setupDataCallRequest.trafficDescriptor, + setupDataCallRequest.matchAllRuleAllowed, (setupDataCallRequest.callback != null) ? new DataServiceCallback(setupDataCallRequest.callback) : null); @@ -690,11 +708,12 @@ public abstract class DataService extends Service { public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, IDataServiceCallback callback) { mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0, new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, - callback)) + trafficDescriptor, matchAllRuleAllowed, callback)) .sendToTarget(); } diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index e0b9a1a9bb5a..81f5fd3b69a9 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -20,6 +20,7 @@ import android.net.LinkProperties; import android.telephony.data.DataProfile; import android.telephony.data.IDataServiceCallback; import android.telephony.data.SliceInfo; +import android.telephony.data.TrafficDescriptor; /** * {@hide} @@ -30,7 +31,9 @@ oneway interface IDataService void removeDataServiceProvider(int slotId); void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, in LinkProperties linkProperties, - int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback); + int pduSessionId, in SliceInfo sliceInfo, + in TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, + IDataServiceCallback callback); void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback); void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback); diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.aidl b/telephony/java/android/telephony/data/TrafficDescriptor.aidl new file mode 100644 index 000000000000..a9c7604a91b6 --- /dev/null +++ b/telephony/java/android/telephony/data/TrafficDescriptor.aidl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** @hide */ +package android.telephony.data; + +parcelable TrafficDescriptor; diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java new file mode 100644 index 000000000000..480379d641b6 --- /dev/null +++ b/telephony/java/android/telephony/data/TrafficDescriptor.java @@ -0,0 +1,111 @@ +/* + * 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.telephony.data; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for URSP traffic + * matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an optional DNN, which, + * if present, must be used for traffic matching; it does not specify the end point to be used for + * the data call. + * @hide + */ +@SystemApi +public final class TrafficDescriptor implements Parcelable { + private final String mDnn; + private final String mOsAppId; + + private TrafficDescriptor(@NonNull Parcel in) { + mDnn = in.readString(); + mOsAppId = in.readString(); + } + + /** + * Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2 + * @param dnn optional DNN, which must be used for traffic matching, if present + * @param osAppId OsId + osAppId of the traffic descriptor + */ + public TrafficDescriptor(@Nullable String dnn, @Nullable String osAppId) { + mDnn = dnn; + mOsAppId = osAppId; + } + + /** + * DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003. + * @return the DNN of this traffic descriptor. + */ + public @Nullable String getDnn() { + return mDnn; + } + + /** + * OsAppId represents the OsId + OsAppId as defined in 3GPP TS 24.526 Section 5.2. + * @return the OS App ID of this traffic descriptor. + */ + public @Nullable String getOsAppId() { + return mOsAppId; + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull @Override + public String toString() { + return "TrafficDescriptor={mDnn=" + mDnn + ", mOsAppId=" + mOsAppId + "}"; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mDnn); + dest.writeString(mOsAppId); + } + + public static final @NonNull Parcelable.Creator<TrafficDescriptor> CREATOR = + new Parcelable.Creator<TrafficDescriptor>() { + @Override + public @NonNull TrafficDescriptor createFromParcel(@NonNull Parcel source) { + return new TrafficDescriptor(source); + } + + @Override + public @NonNull TrafficDescriptor[] newArray(int size) { + return new TrafficDescriptor[size]; + } + }; + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TrafficDescriptor that = (TrafficDescriptor) o; + return Objects.equals(mDnn, that.mDnn) && Objects.equals(mOsAppId, that.mOsAppId); + } + + @Override + public int hashCode() { + return Objects.hash(mDnn, mOsAppId); + } +} diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 151187c5071f..3a99f0e010c6 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -126,6 +126,7 @@ public class PhoneConstants { * connections.<br/> * APN_TYPE_ALL is a special type to indicate that this APN entry can * service all data connections. + * TODO: remove these and use the reference to ApnSetting.TYPE_XXX_STRING instead */ public static final String APN_TYPE_ALL = ApnSetting.TYPE_ALL_STRING; /** APN type for default data traffic */ @@ -153,20 +154,8 @@ public class PhoneConstants { public static final String APN_TYPE_MCX = ApnSetting.TYPE_MCX_STRING; /** APN type for XCAP */ public static final String APN_TYPE_XCAP = ApnSetting.TYPE_XCAP_STRING; - /** Array of all APN types */ - public static final String[] APN_TYPES = {APN_TYPE_DEFAULT, - APN_TYPE_MMS, - APN_TYPE_SUPL, - APN_TYPE_DUN, - APN_TYPE_HIPRI, - APN_TYPE_FOTA, - APN_TYPE_IMS, - APN_TYPE_CBS, - APN_TYPE_IA, - APN_TYPE_EMERGENCY, - APN_TYPE_MCX, - APN_TYPE_XCAP, - }; + // /** APN type for enterprise */ + // public static final String APN_TYPE_ENTERPRISE = ApnSetting.TYPE_ENTERPRISE_STRING; public static final int RIL_CARD_MAX_APPS = 8; diff --git a/test-base/Android.bp b/test-base/Android.bp index 0b7a3981a403..9bd639b63ae0 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -49,6 +49,12 @@ java_sdk_library { compile_dex: true, default_to_stubs: true, + + // Additional hiddenapi annotations are provided in a separate module. + // TODO(b/180295980) - investigate whether this can be removed + hiddenapi_additional_annotations: [ + "android.test.base-hiddenapi-annotations", + ], } // Build the android.test.base_static library @@ -91,8 +97,9 @@ java_library_static { // =============================================== // This contains the android.test classes from android.test.base plus // the com.android.internal.util.Predicate[s] classes. This is only -// intended for inclusion in android.test.legacy and must not be used -// elsewhere. +// intended for inclusion in android.test.legacy and in +// android.test.base-hiddenapi-annotations to avoid a dependency cycle and must +// not be used elsewhere. java_library_static { name: "android.test.base-minus-junit", diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp index d4f52d0fc6cd..1466590ef311 100644 --- a/test-base/hiddenapi/Android.bp +++ b/test-base/hiddenapi/Android.bp @@ -14,11 +14,6 @@ // limitations under the License. // -// Provided solely to contribute information about which hidden parts of the android.test.base -// library are used by apps. The source files are stubs of the actual files in ../src which use the -// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi. -// Relies on the convention that modules with name <x>-hiddenapi provide hiddenapi information for -// module <x> that is on the bootclasspath. package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import @@ -28,14 +23,20 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +// Provided solely to contribute information about which hidden parts of the android.test.base +// library are used by apps. The source files are stubs of the actual files in ../src which use the +// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi. java_library { - name: "android.test.base-hiddenapi", + name: "android.test.base-hiddenapi-annotations", compile_dex: true, srcs: ["src/**/*.java"], libs: [ - "android.test.base", + // Use this instead of `android.test.base` to avoid a dependency cycle + // as `android.test.base` depends on this. + "android.test.base-minus-junit", + "junit", "unsupportedappusage", ], } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index c5447c1ccf71..7d29cdd2b5c5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -17,382 +17,91 @@ package com.android.server.wm.flicker import android.platform.helpers.IAppHelper -import com.android.server.wm.flicker.dsl.EventLogAssertionBuilder -import com.android.server.wm.flicker.dsl.EventLogAssertionBuilderLegacy -import com.android.server.wm.flicker.dsl.LayersAssertionBuilder -import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy -import com.android.server.wm.flicker.dsl.WmAssertionBuilder -import com.android.server.wm.flicker.dsl.WmAssertionBuilderLegacy import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider" const val DOCKED_STACK_DIVIDER = "DockedStackDivider" const val WALLPAPER_TITLE = "Wallpaper" -@JvmOverloads -fun WmAssertionBuilder.statusBarWindowIsAlwaysVisible(bugId: Int = 0) { - all("statusBarWindowIsAlwaysVisible", bugId) { +fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() { + assertWm { this.showsAboveAppWindow(NAV_BAR_LAYER_NAME) } } -@JvmOverloads -fun WmAssertionBuilder.navBarWindowIsAlwaysVisible(bugId: Int = 0) { - all("navBarWindowIsAlwaysVisible", bugId) { +fun FlickerTestParameter.navBarWindowIsAlwaysVisible() { + assertWm { this.showsAboveAppWindow(NAV_BAR_LAYER_NAME) } } -fun WmAssertionBuilder.visibleWindowsShownMoreThanOneConsecutiveEntry( - ignoreWindows: List<String> = emptyList(), - bugId: Int = 0 -) { - all("visibleWindowsShownMoreThanOneConsecutiveEntry", bugId) { - this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoreWindows) - } -} - -fun WmAssertionBuilder.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper, bugId: Int = 0) { - all("launcherReplacesAppWindowAsTopWindow", bugId) { - this.showsAppWindowOnTop(testApp.getPackage()) - .then() - .showsAppWindowOnTop("Launcher") - } -} - -fun WmAssertionBuilder.wallpaperWindowBecomesVisible(bugId: Int = 0) { - all("wallpaperWindowBecomesVisible", bugId) { - this.hidesBelowAppWindow(WALLPAPER_TITLE) - .then() - .showsBelowAppWindow(WALLPAPER_TITLE) - } -} - -fun WmAssertionBuilder.wallpaperWindowBecomesInvisible(bugId: Int = 0) { - all("wallpaperWindowBecomesInvisible", bugId) { - this.showsBelowAppWindow("Wallpaper") - .then() - .hidesBelowAppWindow("Wallpaper") - } -} - -fun WmAssertionBuilder.appWindowAlwaysVisibleOnTop( - packageName: String, - bugId: Int = 0 -) { - all("appWindowAlwaysVisibleOnTop", bugId) { - this.showsAppWindowOnTop(packageName) - } -} - -fun WmAssertionBuilder.appWindowBecomesVisible(appName: String, bugId: Int = 0) { - all("appWindowBecomesVisible", bugId) { - this.hidesAppWindow(appName) - .then() - .showsAppWindow(appName) - } -} - -fun WmAssertionBuilder.appWindowBecomesInVisible(appName: String, bugId: Int = 0) { - all("appWindowBecomesInVisible", bugId) { - this.showsAppWindow(appName) - .then() - .hidesAppWindow(appName) - } -} - -@JvmOverloads -fun LayersAssertionBuilder.noUncoveredRegions( - beginRotation: Int, - endRotation: Int = beginRotation, - allStates: Boolean = true, - bugId: Int = 0 -) { - val startingBounds = WindowUtils.getDisplayBounds(beginRotation) - val endingBounds = WindowUtils.getDisplayBounds(endRotation) - if (allStates) { - all("noUncoveredRegions", bugId) { - if (startingBounds == endingBounds) { - this.coversAtLeastRegion(startingBounds) - } else { - this.coversAtLeastRegion(startingBounds) - .then() - .coversAtLeastRegion(endingBounds) - } - } - } else { - start("noUncoveredRegions_StartingPos") { - this.coversAtLeastRegion(startingBounds) - } - end("noUncoveredRegions_EndingPos") { - this.coversAtLeastRegion(endingBounds) - } - } -} - -@JvmOverloads -fun LayersAssertionBuilder.navBarLayerIsAlwaysVisible( - rotatesScreen: Boolean = false, - bugId: Int = 0 -) { - if (rotatesScreen) { - all("navBarLayerIsAlwaysVisible", bugId) { - this.showsLayer(NAV_BAR_LAYER_NAME) - .then() - .hidesLayer(NAV_BAR_LAYER_NAME) - .then() - .showsLayer(NAV_BAR_LAYER_NAME) - } - } else { - all("navBarLayerIsAlwaysVisible", bugId) { - this.showsLayer(NAV_BAR_LAYER_NAME) - } - } -} - -@JvmOverloads -fun LayersAssertionBuilder.statusBarLayerIsAlwaysVisible( - rotatesScreen: Boolean = false, - bugId: Int = 0 -) { - if (rotatesScreen) { - all("statusBarLayerIsAlwaysVisible", bugId) { - this.showsLayer(STATUS_BAR_WINDOW_NAME) - .then() - hidesLayer(STATUS_BAR_WINDOW_NAME) - .then() - .showsLayer(STATUS_BAR_WINDOW_NAME) - } - } else { - all("statusBarLayerIsAlwaysVisible", bugId) { - this.showsLayer(STATUS_BAR_WINDOW_NAME) - } - } -} - -@JvmOverloads -fun LayersAssertionBuilder.navBarLayerRotatesAndScales( - beginRotation: Int, - endRotation: Int = beginRotation, - bugId: Int = 0 -) { - val startingPos = WindowUtils.getNavigationBarPosition(beginRotation) - val endingPos = WindowUtils.getNavigationBarPosition(endRotation) - - start("navBarLayerRotatesAndScales_StartingPos", bugId) { - this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos) - } - end("navBarLayerRotatesAndScales_EndingPost", bugId) { - this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos) - } - - /*if (startingPos == endingPos) { - all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) { - this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos) - } - }*/ -} - -@JvmOverloads -fun LayersAssertionBuilder.statusBarLayerRotatesScales( - beginRotation: Int, - endRotation: Int = beginRotation, - bugId: Int = 0 -) { - val startingPos = WindowUtils.getStatusBarPosition(beginRotation) - val endingPos = WindowUtils.getStatusBarPosition(endRotation) - - start("statusBarLayerRotatesScales_StartingPos", bugId) { - this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos) - } - end("statusBarLayerRotatesScales_EndingPos", bugId) { - this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos) - } -} - -fun LayersAssertionBuilder.visibleLayersShownMoreThanOneConsecutiveEntry( - ignoreLayers: List<String> = emptyList(), - bugId: Int = 0 -) { - all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId) { - this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoreLayers) - } -} - -fun LayersAssertionBuilder.appLayerReplacesWallpaperLayer(appName: String, bugId: Int = 0) { - all("appLayerReplacesWallpaperLayer", bugId) { - this.showsLayer("Wallpaper") - .then() - .replaceVisibleLayer("Wallpaper", appName) - } -} - -fun LayersAssertionBuilder.wallpaperLayerReplacesAppLayer(testApp: IAppHelper, bugId: Int = 0) { - all("appLayerReplacesWallpaperLayer", bugId) { - this.showsLayer(testApp.getPackage()) - .then() - .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE) - } -} - -fun LayersAssertionBuilder.layerAlwaysVisible(packageName: String, bugId: Int = 0) { - all("layerAlwaysVisible", bugId) { - this.showsLayer(packageName) - } -} - -fun LayersAssertionBuilder.layerBecomesVisible(packageName: String, bugId: Int = 0) { - all("layerBecomesVisible", bugId) { - this.hidesLayer(packageName) - .then() - .showsLayer(packageName) - } -} - -fun LayersAssertionBuilder.layerBecomesInvisible(packageName: String, bugId: Int = 0) { - all("layerBecomesInvisible", bugId) { - this.showsLayer(packageName) - .then() - .hidesLayer(packageName) - } -} - -fun EventLogAssertionBuilder.focusChanges(vararg windows: String, bugId: Int = 0) { - all("focusChanges", bugId) { - this.focusChanges(windows) - } -} - -fun EventLogAssertionBuilder.focusDoesNotChange(bugId: Int = 0) { - all("focusDoesNotChange", bugId) { - this.focusDoesNotChange() - } -} - @JvmOverloads -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.statusBarWindowIsAlwaysVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 +fun FlickerTestParameter.visibleWindowsShownMoreThanOneConsecutiveEntry( + ignoreWindows: List<String> = emptyList() ) { - all("statusBarWindowIsAlwaysVisible", bugId, enabled) { - this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME) - } -} - -@JvmOverloads -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.navBarWindowIsAlwaysVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("navBarWindowIsAlwaysVisible", bugId, enabled) { - this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME) - } -} - -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.visibleWindowsShownMoreThanOneConsecutiveEntry( - ignoreWindows: List<String> = emptyList(), - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("visibleWindowsShownMoreThanOneConsecutiveEntry", bugId, enabled) { + assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoreWindows) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.launcherReplacesAppWindowAsTopWindow( - testApp: IAppHelper, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("launcherReplacesAppWindowAsTopWindow", bugId, enabled) { +fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper) { + assertWm { this.showsAppWindowOnTop(testApp.getPackage()) .then() .showsAppWindowOnTop("Launcher") } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.wallpaperWindowBecomesVisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("wallpaperWindowBecomesVisible", bugId, enabled) { +fun FlickerTestParameter.wallpaperWindowBecomesVisible() { + assertWm { this.hidesBelowAppWindow(WALLPAPER_TITLE) .then() .showsBelowAppWindow(WALLPAPER_TITLE) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.wallpaperWindowBecomesInvisible( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("wallpaperWindowBecomesInvisible", bugId, enabled) { +fun FlickerTestParameter.wallpaperWindowBecomesInvisible() { + assertWm { this.showsBelowAppWindow("Wallpaper") .then() .hidesBelowAppWindow("Wallpaper") } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.appWindowAlwaysVisibleOnTop( - packageName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("appWindowAlwaysVisibleOnTop", bugId, enabled) { +fun FlickerTestParameter.appWindowAlwaysVisibleOnTop(packageName: String) { + assertWm { this.showsAppWindowOnTop(packageName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.appWindowBecomesVisible( - appName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("appWindowBecomesVisible", bugId, enabled) { +fun FlickerTestParameter.appWindowBecomesVisible(appName: String) { + assertWm { this.hidesAppWindow(appName) .then() .showsAppWindow(appName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun WmAssertionBuilderLegacy.appWindowBecomesInVisible( - appName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("appWindowBecomesInVisible", bugId, enabled) { +fun FlickerTestParameter.appWindowBecomesInVisible(appName: String) { + assertWm { this.showsAppWindow(appName) .then() .hidesAppWindow(appName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") @JvmOverloads -fun LayersAssertionBuilderLegacy.noUncoveredRegions( +fun FlickerTestParameter.noUncoveredRegions( beginRotation: Int, endRotation: Int = beginRotation, - allStates: Boolean = true, - bugId: Int = 0, - enabled: Boolean = bugId == 0 + allStates: Boolean = true ) { val startingBounds = WindowUtils.getDisplayBounds(beginRotation) val endingBounds = WindowUtils.getDisplayBounds(endRotation) if (allStates) { - all("noUncoveredRegions", bugId, enabled) { + assertLayers { if (startingBounds == endingBounds) { this.coversAtLeastRegion(startingBounds) } else { @@ -402,24 +111,19 @@ fun LayersAssertionBuilderLegacy.noUncoveredRegions( } } } else { - start("noUncoveredRegions_StartingPos") { + assertLayersStart { this.coversAtLeastRegion(startingBounds) } - end("noUncoveredRegions_EndingPos") { + assertLayersEnd { this.coversAtLeastRegion(endingBounds) } } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") @JvmOverloads -fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible( - rotatesScreen: Boolean = false, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { +fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) { if (rotatesScreen) { - all("navBarLayerIsAlwaysVisible", bugId, enabled) { + assertLayers { this.showsLayer(NAV_BAR_LAYER_NAME) .then() .hidesLayer(NAV_BAR_LAYER_NAME) @@ -427,169 +131,116 @@ fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible( .showsLayer(NAV_BAR_LAYER_NAME) } } else { - all("navBarLayerIsAlwaysVisible", bugId, enabled) { + assertLayers { this.showsLayer(NAV_BAR_LAYER_NAME) } } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") @JvmOverloads -fun LayersAssertionBuilderLegacy.statusBarLayerIsAlwaysVisible( - rotatesScreen: Boolean = false, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { +fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) { if (rotatesScreen) { - all("statusBarLayerIsAlwaysVisible", bugId, enabled) { - this.showsLayer(STATUS_BAR_LAYER_NAME) + assertLayers { + this.showsLayer(STATUS_BAR_WINDOW_NAME) .then() - .hidesLayer(STATUS_BAR_LAYER_NAME) + hidesLayer(STATUS_BAR_WINDOW_NAME) .then() - .showsLayer(STATUS_BAR_LAYER_NAME) + .showsLayer(STATUS_BAR_WINDOW_NAME) } } else { - all("statusBarLayerIsAlwaysVisible", bugId, enabled) { - this.showsLayer(STATUS_BAR_LAYER_NAME) + assertLayers { + this.showsLayer(STATUS_BAR_WINDOW_NAME) } } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") @JvmOverloads -fun LayersAssertionBuilderLegacy.navBarLayerRotatesAndScales( +fun FlickerTestParameter.navBarLayerRotatesAndScales( beginRotation: Int, - endRotation: Int = beginRotation, - bugId: Int = 0, - enabled: Boolean = bugId == 0 + endRotation: Int = beginRotation ) { val startingPos = WindowUtils.getNavigationBarPosition(beginRotation) val endingPos = WindowUtils.getNavigationBarPosition(endRotation) - start("navBarLayerRotatesAndScales_StartingPos", bugId, enabled) { + assertLayersStart { this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos) } - end("navBarLayerRotatesAndScales_EndingPost", bugId, enabled) { + assertLayersEnd { this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos) } - - if (startingPos == endingPos) { - all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) { - this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos) - } - } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") @JvmOverloads -fun LayersAssertionBuilderLegacy.statusBarLayerRotatesScales( +fun FlickerTestParameter.statusBarLayerRotatesScales( beginRotation: Int, - endRotation: Int = beginRotation, - bugId: Int = 0, - enabled: Boolean = bugId == 0 + endRotation: Int = beginRotation ) { val startingPos = WindowUtils.getStatusBarPosition(beginRotation) val endingPos = WindowUtils.getStatusBarPosition(endRotation) - start("statusBarLayerRotatesScales_StartingPos", bugId, enabled) { - this.hasVisibleRegion(STATUS_BAR_LAYER_NAME, startingPos) + assertLayersStart { + this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos) } - end("statusBarLayerRotatesScales_EndingPos", bugId, enabled) { - this.hasVisibleRegion(STATUS_BAR_LAYER_NAME, endingPos) + assertLayersEnd { + this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.visibleLayersShownMoreThanOneConsecutiveEntry( - ignoreLayers: List<String> = kotlin.collections.emptyList(), - bugId: Int = 0, - enabled: Boolean = bugId == 0 +@JvmOverloads +fun FlickerTestParameter.visibleLayersShownMoreThanOneConsecutiveEntry( + ignoreLayers: List<String> = emptyList() ) { - all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId, enabled) { + assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoreLayers) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.appLayerReplacesWallpaperLayer( - appName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("appLayerReplacesWallpaperLayer", bugId, enabled) { +fun FlickerTestParameter.appLayerReplacesWallpaperLayer(appName: String) { + assertLayers { this.showsLayer("Wallpaper") .then() .replaceVisibleLayer("Wallpaper", appName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.wallpaperLayerReplacesAppLayer( - testApp: IAppHelper, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("appLayerReplacesWallpaperLayer", bugId, enabled) { +fun FlickerTestParameter.wallpaperLayerReplacesAppLayer(testApp: IAppHelper) { + assertLayers { this.showsLayer(testApp.getPackage()) .then() .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.layerAlwaysVisible( - packageName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("layerAlwaysVisible", bugId, enabled) { +fun FlickerTestParameter.layerAlwaysVisible(packageName: String) { + assertLayers { this.showsLayer(packageName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.layerBecomesVisible( - packageName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("layerBecomesVisible", bugId, enabled) { +fun FlickerTestParameter.layerBecomesVisible(packageName: String) { + assertLayers { this.hidesLayer(packageName) .then() .showsLayer(packageName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun LayersAssertionBuilderLegacy.layerBecomesInvisible( - packageName: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("layerBecomesInvisible", bugId, enabled) { +fun FlickerTestParameter.layerBecomesInvisible(packageName: String) { + assertLayers { this.showsLayer(packageName) .then() .hidesLayer(packageName) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun EventLogAssertionBuilderLegacy.focusChanges( - vararg windows: String, - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("focusChanges", bugId, enabled) { +fun FlickerTestParameter.focusChanges(vararg windows: String) { + assertEventLog { this.focusChanges(windows) } } -@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)") -fun EventLogAssertionBuilderLegacy.focusDoesNotChange( - bugId: Int = 0, - enabled: Boolean = bugId == 0 -) { - all("focusDoesNotChange", bugId, enabled) { +fun FlickerTestParameter.focusDoesNotChange() { + assertEventLog { this.focusDoesNotChange() } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index c507841ffb71..fbf18d45afd8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -16,11 +16,17 @@ package com.android.server.wm.flicker.close +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible @@ -35,12 +41,12 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -51,86 +57,119 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseAppBackButtonTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseAppBackButtonTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = SimpleAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + this.setRotation(testSpec.config.startRotation) + testApp.launchViaIntent(wmHelper) + } + } + transitions { + device.pressBack() + wmHelper.waitForHomeActivityVisible() + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) + } + test { + testApp.exit() + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun launcherReplacesAppWindowAsTopWindow() = + testSpec.launcherReplacesAppWindowAsTopWindow(testApp) + + @Presubmit + @Test + fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible() + + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + Surface.ROTATION_0) + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest(bugId = 173684672) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 173684672) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = SimpleAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - this.setRotation(configuration.startRotation) - testApp.launchViaIntent(wmHelper) - } - } - transitions { - device.pressBack() - wmHelper.waitForHomeActivityVisible() - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - testApp.exit() - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - launcherReplacesAppWindowAsTopWindow(testApp) - wallpaperWindowBecomesVisible() - } - - layersTrace { - noUncoveredRegions(configuration.startRotation, - Surface.ROTATION_0) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - wallpaperLayerReplacesAppLayer(testApp) - - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - - flaky { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173684672) - } - - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173684672) - - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - } - } + fun getParams(): List<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index d1c3efe35c54..08d2b7c206bf 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -16,12 +16,17 @@ package com.android.server.wm.flicker.close +import android.app.Instrumentation import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible @@ -36,12 +41,12 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -50,88 +55,121 @@ import org.junit.runners.Parameterized * Test app closes by pressing home button. * To run this test: `atest FlickerTests:CloseAppHomeButtonTest` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseAppHomeButtonTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseAppHomeButtonTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = SimpleAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + testApp.launchViaIntent(wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + device.pressHome() + wmHelper.waitForHomeActivityVisible() + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) + } + test { + testApp.exit() + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun launcherReplacesAppWindowAsTopWindow() = + testSpec.launcherReplacesAppWindowAsTopWindow(testApp) + + @Presubmit + @Test + fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible() + + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions( + testSpec.config.startRotation, Surface.ROTATION_0) + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest(bugId = 173689015) + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 173689015) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = SimpleAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.startRotation) - } - } - transitions { - device.pressHome() - wmHelper.waitForHomeActivityVisible() - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - testApp.exit() - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - launcherReplacesAppWindowAsTopWindow(testApp) - wallpaperWindowBecomesVisible() - } - - layersTrace { - noUncoveredRegions(configuration.startRotation, - Surface.ROTATION_0) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - wallpaperLayerReplacesAppLayer(testApp) - - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - - flaky { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173689015) - } - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173689015) - - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt index 323236ed9962..f7e749311442 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt @@ -16,13 +16,9 @@ package com.android.server.wm.flicker.helpers -import android.os.Bundle import android.os.RemoteException -import android.platform.helpers.IAppHelper import android.view.Surface import com.android.server.wm.flicker.Flicker -import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.startRotation /** * Changes the device [rotation] and wait for the rotation animation to complete @@ -47,128 +43,4 @@ fun Flicker.setRotation(rotation: Int) { } catch (e: RemoteException) { throw RuntimeException(e) } -} - -/** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param beginRotation Initial screen rotation - * @param endRotation End screen rotation (if any, otherwise use same as initial) - * - * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION> -</END_ROTATION></BEGIN_ROTATION></APP></NAME> */ -fun buildTestTag( - testName: String, - app: IAppHelper, - beginRotation: Int, - endRotation: Int -): String { - return buildTestTag( - testName, app.launcherName, beginRotation, endRotation, app2 = null, extraInfo = "") -} - -/** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param configuration Configuration for the test - * @param extraInfo Additional information to append to the tag - * - * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION> -</END_ROTATION></BEGIN_ROTATION></APP></NAME> */ -@JvmOverloads -fun buildTestTag( - testName: String, - configuration: Bundle, - extraInfo: String = "" -): String { - return buildTestTag(testName, - app = null, - beginRotation = configuration.startRotation, - endRotation = configuration.endRotation, - app2 = null, - extraInfo = extraInfo) -} - -/** - * Build a test tag for the test - * @param configuration Configuration for the test - * @param extraInfo Additional information to append to the tag - * - * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION> -</END_ROTATION></BEGIN_ROTATION></APP></NAME> */ -@JvmOverloads -fun buildTestTag( - configuration: Bundle, - extraInfo: String = "" -): String { - return buildTestTag(testName = null, - app = null, - beginRotation = configuration.startRotation, - endRotation = configuration.endRotation, - app2 = null, - extraInfo = extraInfo) -} - -/** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param configuration Configuration for the test - * @param extraInfo Additional information to append to the tag - * - * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION> -</END_ROTATION></BEGIN_ROTATION></APP></NAME> */ -@JvmOverloads -fun buildTestTag( - testName: String, - app: IAppHelper?, - configuration: Bundle, - extraInfo: String = "" -): String { - return buildTestTag(testName, app?.launcherName ?: "", configuration.startRotation, - configuration.endRotation, app2 = null, extraInfo = extraInfo) -} - -/** - * Build a test tag for the test - * @param testName Name of the transition(s) being tested - * @param app App being launcher - * @param app2 Second app being launched (if any) - * @param beginRotation Initial screen rotation - * @param endRotation End screen rotation (if any, otherwise use same as initial) - * @param extraInfo Additional information to append to the tag - * - * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>] -</EXTRA></NAME> */ -fun buildTestTag( - testName: String?, - app: String?, - beginRotation: Int, - endRotation: Int, - app2: String?, - extraInfo: String -): String { - var testTag = "" - if (testName != null) { - testTag += testName - } - if (app != null) { - testTag += "__$app" - } - if (app2 != null) { - testTag += "-$app2" - } - testTag += "__${Surface.rotationToString(beginRotation)}" - if (endRotation != beginRotation) { - testTag += "-${Surface.rotationToString(endRotation)}" - } - if (extraInfo.isNotEmpty()) { - testTag += "__$extraInfo" - } - - if (testTag.startsWith("__")) { - testTag = testTag.drop(2) - } - return testTag -} +}
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index c7736f825e27..47eaddfa1f3a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -16,14 +16,19 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry @@ -37,7 +42,9 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -48,79 +55,116 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseImeAutoOpenWindowToAppTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + testApp.launchViaIntent(wmHelper) + testApp.openIME(device, wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + teardown { + test { + testApp.exit() + wmHelper.waitForAppTransitionIdle() + this.setRotation(Surface.ROTATION_0) + } + } + transitions { + testApp.closeIME(device, wmHelper) + } + } + } + + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + + @Postsubmit + @Test + fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp) + + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) + + @Postsubmit + @Test + fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible() + + @Postsubmit + @Test + fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - val testApp = ImeAppAutoFocusHelper(instrumentation, - configuration.startRotation) - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - testApp.launchViaIntent(wmHelper) - testApp.openIME(device, wmHelper) - this.setRotation(configuration.startRotation) - } - } - teardown { - test { - testApp.exit() - wmHelper.waitForAppTransitionIdle() - this.setRotation(Surface.ROTATION_0) - } - } - transitions { - testApp.closeIME(device, wmHelper) - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - postsubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - imeAppWindowIsAlwaysVisible(testApp) - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation) - imeLayerBecomesInvisible() - imeAppLayerIsAlwaysVisible(testApp) - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation) - statusBarLayerRotatesScales(configuration.startRotation) - } - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation) - statusBarLayerRotatesScales(configuration.startRotation) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index aa24456c652f..38a88d372da4 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -16,14 +16,18 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry @@ -37,7 +41,9 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -48,93 +54,151 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseImeAutoOpenWindowToHomeTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + testApp.launchViaIntent(wmHelper) + testApp.openIME(device, wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + teardown { + test { + testApp.exit() + this.setRotation(Surface.ROTATION_0) + } + } + transitions { + device.pressHome() + wmHelper.waitForHomeActivityVisible() + wmHelper.waitImeWindowGone() + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + + @Presubmit + @Test + fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible() + + @Presubmit + @Test + fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp) + + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + Surface.ROTATION_0) + + @Presubmit + @Test + fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible() + + @Presubmit + @Test + fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerIsAlwaysVisible() + } + + @FlakyTest + @Test + fun navBarLayerIsAlwaysVisible_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerIsAlwaysVisible() + } + + @FlakyTest + @Test + fun statusBarLayerIsAlwaysVisible_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + } + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + } companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - val testApp = ImeAppAutoFocusHelper(instrumentation, - configuration.startRotation) - withTestName { - buildTestTag(configuration) - } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - testApp.launchViaIntent(wmHelper) - testApp.openIME(device, wmHelper) - this.setRotation(configuration.startRotation) - } - } - teardown { - test { - testApp.exit() - this.setRotation(Surface.ROTATION_0) - } - } - transitions { - device.pressHome() - wmHelper.waitForHomeActivityVisible() - wmHelper.waitImeWindowGone() - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - - imeWindowBecomesInvisible() - imeAppWindowBecomesInvisible(testApp) - } - - layersTrace { - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) - imeLayerBecomesInvisible() - imeAppLayerBecomesInvisible(testApp) - - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - } - } - } - - flaky { - layersTrace { - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt index 2bd5abb640e5..476708c42c4c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt @@ -16,13 +16,18 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -33,10 +38,10 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -47,63 +52,97 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseImeWindowToAppTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.launchViaIntent() + this.setRotation(testSpec.config.startRotation) + } + eachRun { + testApp.openIME(device, wmHelper) + } + } + teardown { + test { + testApp.exit() + this.setRotation(Surface.ROTATION_0) + } + } + transitions { + testApp.closeIME(device, wmHelper) + } + } + } + + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + + @Postsubmit + @Test + fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp) + + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + + @FlakyTest + @Test + fun statusBarLayerRotatesScales() = + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation) + + @Postsubmit + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @Postsubmit + @Test + fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible() + + @Postsubmit + @Test + fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp) companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = ImeAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - testApp.launchViaIntent() - this.setRotation(configuration.startRotation) - } - eachRun { - testApp.openIME(device, wmHelper) - } - } - teardown { - test { - testApp.exit() - this.setRotation(Surface.ROTATION_0) - } - } - transitions { - testApp.closeIME(device, wmHelper) - } - assertions { - postsubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - imeAppWindowIsAlwaysVisible(testApp) - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation) - navBarLayerRotatesAndScales(configuration.startRotation) - statusBarLayerRotatesScales(configuration.startRotation) - visibleLayersShownMoreThanOneConsecutiveEntry() - imeLayerBecomesInvisible() - imeAppLayerIsAlwaysVisible(testApp) - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 7b61bb58446c..ac140f505076 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -16,28 +16,33 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry +import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -47,90 +52,126 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseImeWindowToHomeTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + testApp.launchViaIntent(wmHelper) + this.setRotation(testSpec.config.startRotation) + testApp.openIME(device, wmHelper) + } + } + transitions { + device.pressHome() + wmHelper.waitForHomeActivityVisible() + wmHelper.waitImeWindowGone() + } + teardown { + eachRun { + device.pressHome() + wmHelper.waitForHomeActivityVisible() + } + test { + testApp.exit() + this.setRotation(Surface.ROTATION_0) + } + } + } + } + + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + + @Postsubmit + @Test + fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible() + + @Postsubmit + @Test + fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp) + + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + Surface.ROTATION_0) + + @Postsubmit + @Test + fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible() + + @Postsubmit + @Test + fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp) + + @Postsubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Postsubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE)) + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = ImeAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.startRotation) - testApp.openIME(device, wmHelper) - } - } - transitions { - device.pressHome() - wmHelper.waitForHomeActivityVisible() - wmHelper.waitImeWindowGone() - } - teardown { - eachRun { - device.pressHome() - wmHelper.waitForHomeActivityVisible() - } - test { - testApp.exit() - this.setRotation(Surface.ROTATION_0) - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - postsubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - imeWindowBecomesInvisible() - imeAppWindowBecomesInvisible(testApp) - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - imeLayerBecomesInvisible() - imeAppLayerBecomesInvisible(testApp) - noUncoveredRegions(configuration.startRotation, - Surface.ROTATION_0) - - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(IME_WINDOW_TITLE)) - - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0) - statusBarLayerRotatesScales(configuration.startRotation, - Surface.ROTATION_0) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt index cfdd8564128f..212644c04505 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt @@ -17,85 +17,75 @@ package com.android.server.wm.flicker.ime import android.platform.helpers.IAppHelper -import com.android.server.wm.flicker.dsl.LayersAssertionBuilder -import com.android.server.wm.flicker.dsl.WmAssertionBuilder +import com.android.server.wm.flicker.FlickerTestParameter const val IME_WINDOW_TITLE = "InputMethod" -@JvmOverloads -fun LayersAssertionBuilder.imeLayerBecomesVisible(bugId: Int = 0) { - all("imeLayerBecomesVisible", bugId) { +fun FlickerTestParameter.imeLayerBecomesVisible() { + assertLayers { this.hidesLayer(IME_WINDOW_TITLE) - .then() - .showsLayer(IME_WINDOW_TITLE) + .then() + .showsLayer(IME_WINDOW_TITLE) } } -@JvmOverloads -fun LayersAssertionBuilder.imeLayerBecomesInvisible(bugId: Int = 0) { - all("imeLayerBecomesInvisible", bugId) { +fun FlickerTestParameter.imeLayerBecomesInvisible() { + assertLayers { this.showsLayer(IME_WINDOW_TITLE) - .then() - .hidesLayer(IME_WINDOW_TITLE) + .then() + .hidesLayer(IME_WINDOW_TITLE) } } -@JvmOverloads -fun LayersAssertionBuilder.imeAppLayerIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) { - all("imeAppLayerIsAlwaysVisible", bugId) { +fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) { + assertLayers { this.showsLayer(testApp.getPackage()) } } -@JvmOverloads -fun WmAssertionBuilder.imeAppWindowIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) { - all("imeAppWindowIsAlwaysVisible", bugId) { +fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(testApp: IAppHelper) { + assertWm { this.showsAppWindowOnTop(testApp.getPackage()) } } -@JvmOverloads -fun WmAssertionBuilder.imeWindowBecomesVisible(bugId: Int = 0) { - all("imeWindowBecomesVisible", bugId) { +fun FlickerTestParameter.imeWindowBecomesVisible() { + assertWm { this.hidesNonAppWindow(IME_WINDOW_TITLE) - .then() - .showsNonAppWindow(IME_WINDOW_TITLE) + .then() + .showsNonAppWindow(IME_WINDOW_TITLE) } } -@JvmOverloads -fun WmAssertionBuilder.imeWindowBecomesInvisible(bugId: Int = 0) { - all("imeWindowBecomesInvisible", bugId) { +fun FlickerTestParameter.imeWindowBecomesInvisible() { + assertWm { this.showsNonAppWindow(IME_WINDOW_TITLE) - .then() - .hidesNonAppWindow(IME_WINDOW_TITLE) + .then() + .hidesNonAppWindow(IME_WINDOW_TITLE) } } -@JvmOverloads -fun WmAssertionBuilder.imeAppWindowBecomesVisible(windowName: String, bugId: Int = 0) { - all("imeAppWindowBecomesVisible", bugId) { +fun FlickerTestParameter.imeAppWindowBecomesVisible(windowName: String) { + assertWm { this.hidesAppWindow(windowName) - .then() - .showsAppWindow(windowName) + .then() + .showsAppWindow(windowName) } } -@JvmOverloads -fun WmAssertionBuilder.imeAppWindowBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) { - all("imeAppWindowBecomesInvisible", bugId) { +fun FlickerTestParameter.imeAppWindowBecomesInvisible(testApp: IAppHelper) { + assertWm { this.showsAppWindowOnTop(testApp.getPackage()) - .then() - .appWindowNotOnTop(testApp.getPackage()) + .then() + .appWindowNotOnTop(testApp.getPackage()) } } -@JvmOverloads -fun LayersAssertionBuilder.imeAppLayerBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) { - all("imeAppLayerBecomesInvisible", bugId) { +fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) { + assertLayers { this.skipUntilFirstAssertion() - .showsLayer(testApp.getPackage()) - .then() - .hidesLayer(testApp.getPackage()) + .showsLayer(testApp.getPackage()) + .then() + .hidesLayer(testApp.getPackage()) } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt index 9e94d6e49527..c7a5178a6693 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt @@ -16,13 +16,17 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -32,14 +36,16 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop -import com.android.server.wm.flicker.helpers.isRotated +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.layerAlwaysVisible import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -50,80 +56,119 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class OpenImeWindowTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class OpenImeWindowTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.launchViaIntent(wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + testApp.openIME(device, wmHelper) + } + teardown { + eachRun { + testApp.closeIME(device, wmHelper) + } + test { + testApp.exit() + this.setRotation(Surface.ROTATION_0) + } + } + } + } + + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Postsubmit + @Test + fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible() + + @Postsubmit + @Test + fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`) + + @Postsubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Postsubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation) + + @Postsubmit + @Test + fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible() + + @Postsubmit + @Test + fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`) + + @Postsubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + } + + @Postsubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation) + } + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = ImeAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.startRotation) - } - } - transitions { - testApp.openIME(device, wmHelper) - } - teardown { - eachRun { - testApp.closeIME(device, wmHelper) - } - test { - testApp.exit() - this.setRotation(Surface.ROTATION_0) - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - postsubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - - imeWindowBecomesVisible() - appWindowAlwaysVisibleOnTop(testApp.`package`) - } - - layersTrace { - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation) - imeLayerBecomesVisible() - layerAlwaysVisible(testApp.`package`) - - if (!isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation) - statusBarLayerRotatesScales(configuration.startRotation) - } - } - } - - flaky { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry() - } - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - - if (isRotated) { - navBarLayerRotatesAndScales(configuration.startRotation) - statusBarLayerRotatesScales(configuration.startRotation) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt index 52549a23c9bb..0cd5d7999a58 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt @@ -16,14 +16,18 @@ package com.android.server.wm.flicker.ime +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -31,18 +35,20 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.endRotation -import com.android.server.wm.flicker.helpers.isRotated import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.testapp.ActivityOptions +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -53,89 +59,132 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class ReOpenImeWindowTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation) + private val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.launchViaIntent(wmHelper) + testApp.openIME(device, wmHelper) + } + eachRun { + device.pressRecentApps() + wmHelper.waitImeWindowGone() + wmHelper.waitForAppTransitionIdle() + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + device.reopenAppFromOverview(wmHelper) + wmHelper.waitImeWindowShown() + } + teardown { + test { + this.setRotation(Surface.ROTATION_0) + testApp.exit() + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible() + + @Presubmit + @Test + fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible() + + @Presubmit + @Test + fun imeAppWindowBecomesVisible() = + testSpec.imeAppWindowBecomesVisible(testAppComponentName.className) + + @Presubmit + @Test + // During testing the launcher is always in portrait mode + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + testSpec.config.endRotation) + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible() + + @Presubmit + @Test + fun appLayerReplacesWallpaperLayer() = + testSpec.appLayerReplacesWallpaperLayer(testAppComponentName.className) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation) + } + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 1) { configuration -> - val testApp = ImeAppAutoFocusHelper(instrumentation, - configuration.startRotation) - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - testApp.launchViaIntent(wmHelper) - testApp.openIME(device, wmHelper) - } - eachRun { - device.pressRecentApps() - wmHelper.waitImeWindowGone() - wmHelper.waitForAppTransitionIdle() - this.setRotation(configuration.startRotation) - } - } - transitions { - device.reopenAppFromOverview(wmHelper) - wmHelper.waitImeWindowShown() - } - teardown { - test { - this.setRotation(Surface.ROTATION_0) - testApp.exit() - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - - imeWindowBecomesVisible() - imeAppWindowBecomesVisible(testAppComponentName.className) - wallpaperWindowBecomesInvisible() - } - - layersTrace { - noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation) - statusBarLayerIsAlwaysVisible() - navBarLayerIsAlwaysVisible() - imeLayerBecomesVisible() - appLayerReplacesWallpaperLayer(testAppComponentName.className) - - if (!isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - - if (isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 1) } } -}
\ No newline at end of file +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt index be3fa5fa3cdf..130860d31ac1 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.launch import android.platform.helpers.IAppHelper -import com.android.server.wm.flicker.dsl.WmAssertionBuilder +import com.android.server.wm.flicker.FlickerTestParameter -fun WmAssertionBuilder.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper, bugId: Int = 0) { - all("appWindowReplacesLauncherAsTopWindow", bugId) { +fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) { + assertWm { this.showsAppWindowOnTop("Launcher") - .then() - .showsAppWindowOnTop("Snapshot", testApp.getPackage()) + .then() + .showsAppWindowOnTop("Snapshot", testApp.getPackage()) } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt index 0ec0b04339cd..74f002d67229 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt @@ -16,14 +16,17 @@ package com.android.server.wm.flicker.launch +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -39,9 +42,11 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.helpers.isRotated +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -52,85 +57,122 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class OpenAppColdTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class OpenAppColdTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = SimpleAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + eachRun { + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + testApp.launchViaIntent(wmHelper) + // wmHelper.waitForFullScreenApp(testApp.component) + } + teardown { + eachRun { + testApp.exit() + wmHelper.waitForAppTransitionIdle() + this.setRotation(Surface.ROTATION_0) + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun appWindowReplacesLauncherAsTopWindow() = + testSpec.appWindowReplacesLauncherAsTopWindow(testApp) + + @Presubmit + @Test + fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible() + + @Presubmit + @Test + // During testing the launcher is always in portrait mode + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + Surface.ROTATION_0) + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun appLayerReplacesWallpaperLayer() = + testSpec.appLayerReplacesWallpaperLayer(testApp.`package`) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`) + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = SimpleAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - this.setRotation(configuration.startRotation) - } - } - transitions { - testApp.open() - wmHelper.waitForFullScreenApp(testApp.component) - } - teardown { - eachRun { - testApp.exit() - wmHelper.waitForAppTransitionIdle() - this.setRotation(Surface.ROTATION_0) - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - appWindowReplacesLauncherAsTopWindow(testApp) - wallpaperWindowBecomesInvisible() - } - - layersTrace { - // During testing the launcher is always in portrait mode - noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - appLayerReplacesWallpaperLayer(testApp.`package`) - - if (!isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - - eventLog { - focusChanges("NexusLauncherActivity", testApp.`package`) - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - - if (isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt index 5fb050927dad..e2a258aea239 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt @@ -16,17 +16,22 @@ package com.android.server.wm.flicker.launch +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -40,9 +45,11 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.helpers.isRotated +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -53,97 +60,115 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class OpenAppFromOverviewTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { +class OpenAppFromOverviewTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = SimpleAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.launchViaIntent(wmHelper) + } + eachRun { + device.pressHome() + wmHelper.waitForAppTransitionIdle() + device.pressRecentApps() + wmHelper.waitForAppTransitionIdle() + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + device.reopenAppFromOverview(wmHelper) + wmHelper.waitForFullScreenApp(testApp.component) + } + teardown { + test { + testApp.exit() + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Test + fun appWindowReplacesLauncherAsTopWindow() = + testSpec.appWindowReplacesLauncherAsTopWindow(testApp) + + @Test + fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible() + + @Presubmit + @Test + fun appLayerReplacesWallpaperLayer() = + testSpec.appLayerReplacesWallpaperLayer(testApp.`package`) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`) + + @Postsubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 141361128) + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0, + testSpec.config.endRotation) + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = SimpleAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation, repetitions = 5) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - testApp.launchViaIntent(wmHelper) - } - eachRun { - device.pressHome() - wmHelper.waitForAppTransitionIdle() - device.pressRecentApps() - wmHelper.waitForAppTransitionIdle() - this.setRotation(configuration.startRotation) - } - } - transitions { - device.reopenAppFromOverview(wmHelper) - wmHelper.waitForFullScreenApp(testApp.component) - } - teardown { - test { - testApp.exit() - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - appWindowReplacesLauncherAsTopWindow(testApp) - wallpaperWindowBecomesInvisible() - } - - layersTrace { - appLayerReplacesWallpaperLayer(testApp.`package`) - - if (!isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } else { - statusBarLayerIsAlwaysVisible() - navBarLayerIsAlwaysVisible() - } - } - - eventLog { - focusChanges("NexusLauncherActivity", testApp.`package`) - } - } - - postsubmit { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry() - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation, - bugId = 141361128) - - if (isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } else { - statusBarLayerIsAlwaysVisible() - navBarLayerIsAlwaysVisible() - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests(repetitions = 5) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index 1f375a5cdea8..386dafc590af 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -16,14 +16,17 @@ package com.android.server.wm.flicker.launch +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -36,12 +39,13 @@ import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.helpers.isRotated +import org.junit.Assume import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -52,89 +56,122 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class OpenAppWarmTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) { +class OpenAppWarmTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val testApp = SimpleAppHelper(instrumentation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.launchViaIntent(wmHelper) + // wmHelper.waitForFullScreenApp(testApp.component) + } + eachRun { + device.pressHome() + wmHelper.waitForHomeActivityVisible() + this.setRotation(testSpec.config.startRotation) + } + } + transitions { + testApp.launchViaIntent(wmHelper) + wmHelper.waitForFullScreenApp(testApp.component) + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) + } + test { + testApp.exit() + } + } + } + } + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun appWindowReplacesLauncherAsTopWindow() = + testSpec.appWindowReplacesLauncherAsTopWindow(testApp) + + @Presubmit + @Test + fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible() + + @Presubmit + @Test + // During testing the launcher is always in portrait mode + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + Surface.ROTATION_0) + + @Presubmit + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @Presubmit + @Test + fun appLayerReplacesWallpaperLayer() = + testSpec.appLayerReplacesWallpaperLayer(testApp.`package`) + + @Presubmit + @Test + fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`) + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = SimpleAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance() - .buildTest(instrumentation) { configuration -> - withTestName { buildTestTag(configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - testApp.open() - wmHelper.waitForFullScreenApp(testApp.component) - } - eachRun { - device.pressHome() - wmHelper.waitForHomeActivityVisible() - this.setRotation(configuration.startRotation) - } - } - transitions { - testApp.open() - wmHelper.waitForFullScreenApp(testApp.component) - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - testApp.exit() - } - } - assertions { - val isRotated = configuration.startRotation.isRotated() - - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - - appWindowReplacesLauncherAsTopWindow(testApp) - wallpaperWindowBecomesInvisible() - } - - layersTrace { - // During testing the launcher is always in portrait mode - noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation) - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() - appLayerReplacesWallpaperLayer(testApp.`package`) - - if (!isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - - eventLog { - focusChanges("NexusLauncherActivity", testApp.`package`) - } - } - - flaky { - layersTrace { - visibleLayersShownMoreThanOneConsecutiveEntry() - - if (isRotated) { - navBarLayerRotatesAndScales(Surface.ROTATION_0, - configuration.endRotation) - statusBarLayerRotatesScales(Surface.ROTATION_0, - configuration.endRotation) - } - } - } - } - } + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 7bfdd96b9af8..3cc509fe2b8e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -17,28 +17,27 @@ package com.android.server.wm.flicker.rotation import android.os.Bundle +import android.platform.test.annotations.Presubmit +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.focusDoesNotChange import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.helpers.StandardAppHelper -import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.startRotation -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry +import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -49,78 +48,95 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class ChangeAppRotationTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : RotationTransition(InstrumentationRegistry.getInstrumentation()) { - override val testApp: StandardAppHelper - get() = SimpleAppHelper(instrumentation) + testSpec: FlickerTestParameter +) : RotationTransition(testSpec) { + override val testApp = SimpleAppHelper(instrumentation) + override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = emptyMap() + + @Presubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + testSpec.config.endRotation, allStates = false) + + @Presubmit + @Test + fun screenshotLayerBecomesInvisible() { + testSpec.assertLayers { + this.showsLayer(testApp.getPackage()) + .then() + .showsLayer(SCREENSHOT_LAYER) + .then() + .showsLayer(testApp.getPackage()) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @FlakyTest(bugId = 140855415) + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 140855415) + @Test + fun appLayerRotates_StartingPos() { + testSpec.assertLayersStart { + this.hasVisibleRegion(testApp.getPackage(), startingPos) + } + } + + @FlakyTest(bugId = 140855415) + @Test + fun appLayerRotates_EndingPos() { + testSpec.assertLayersEnd { + this.hasVisibleRegion(testApp.getPackage(), endingPos) + } + } - override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = emptyMap() + @FlakyTest(bugId = 151179149) + @Test + fun focusDoesNotChange() = testSpec.focusDoesNotChange() + companion object { private const val SCREENSHOT_LAYER = "RotationLayer" - @Parameterized.Parameters(name = "{0}1}") + @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { buildTestTag(configuration) } - assertions { - presubmit { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - visibleWindowsShownMoreThanOneConsecutiveEntry() - } - - layersTrace { - noUncoveredRegions(configuration.startRotation, - configuration.endRotation, allStates = false) - - all("screenshotLayerBecomesInvisible") { - this.showsLayer(testApp.getPackage()) - .then() - .showsLayer(SCREENSHOT_LAYER) - .then() - .showsLayer(testApp.getPackage()) - } - } - } - - flaky { - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - navBarLayerRotatesAndScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) - statusBarLayerRotatesScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) - visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 140855415) - - val startingPos = WindowUtils.getDisplayBounds( - configuration.startRotation) - val endingPos = WindowUtils.getDisplayBounds( - configuration.endRotation) - - start("appLayerRotates_StartingPos", bugId = 140855415) { - this.hasVisibleRegion(testApp.getPackage(), startingPos) - } - - end("appLayerRotates_EndingPos", bugId = 140855415) { - this.hasVisibleRegion(testApp.getPackage(), endingPos) - } - } - - eventLog { - focusDoesNotChange(bugId = 151179149) - } - } - } - } - - return FlickerTestRunnerFactory.getInstance() - .buildRotationTest(instrumentation, transition, testSpec, repetitions = 5) + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigRotationTests(repetitions = 5) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index b871e949cb19..04ab84dfcd8e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -18,29 +18,39 @@ package com.android.server.wm.flicker.rotation import android.app.Instrumentation import android.os.Bundle +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.StandardAppHelper +import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -abstract class RotationTransition(protected val instrumentation: Instrumentation) { - abstract val testApp: StandardAppHelper - abstract fun getAppLaunchParams(configuration: Bundle): Map<String, String> +abstract class RotationTransition(protected val testSpec: FlickerTestParameter) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation) - protected open val transition: FlickerBuilder.(Bundle) -> Unit - get() = { configuration -> - repeat { configuration.repetitions } + protected abstract val testApp: StandardAppHelper + protected abstract fun getAppLaunchParams(configuration: Bundle): Map<String, String> + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } setup { test { device.wakeUpAndGoToHomeScreen() - val extras = getAppLaunchParams(configuration) + val extras = getAppLaunchParams(testSpec.config) testApp.launchViaIntent(wmHelper, stringExtras = extras) } eachRun { - this.setRotation(configuration.startRotation) + this.setRotation(testSpec.config.startRotation) } } teardown { @@ -49,7 +59,8 @@ abstract class RotationTransition(protected val instrumentation: Instrumentation } } transitions { - this.setRotation(configuration.endRotation) + this.setRotation(testSpec.config.endRotation) } } + } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 78614640a372..ef1aeadb31bc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -17,31 +17,30 @@ package com.android.server.wm.flicker.rotation import android.os.Bundle +import android.platform.test.annotations.Presubmit +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerTestRunner -import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.focusDoesNotChange -import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop -import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper -import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.layerAlwaysVisible -import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry +import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry import org.junit.FixMethodOrder +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -52,116 +51,108 @@ import org.junit.runners.Parameterized */ @RequiresDevice @RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class SeamlessAppRotationTest( - testSpec: FlickerTestRunnerFactory.TestSpec -) : FlickerTestRunner(testSpec) { - companion object : RotationTransition(InstrumentationRegistry.getInstrumentation()) { - override val testApp: StandardAppHelper - get() = SeamlessRotationAppHelper(instrumentation) + testSpec: FlickerTestParameter +) : RotationTransition(testSpec) { + override val testApp = SeamlessRotationAppHelper(instrumentation) + + override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = mapOf( + ActivityOptions.EXTRA_STARVE_UI_THREAD to configuration.starveUiThread.toString() + ) + + @Presubmit + @Test + fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + + @Presubmit + @Test + fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`) + + @Presubmit + @Test + fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`) + + @FlakyTest(bugId = 140855415) + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 140855415) + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() + + @FlakyTest(bugId = 147659548) + @Test + fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, + testSpec.config.endRotation, allStates = false) + + @FlakyTest + @Test + fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @FlakyTest + @Test + fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales( + testSpec.config.startRotation, testSpec.config.endRotation) + + @FlakyTest + @Test + fun visibleLayersShownMoreThanOneConsecutiveEntry() = + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + + @FlakyTest(bugId = 147659548) + @Test + fun appLayerRotates() { + testSpec.assertLayers { + this.hasVisibleRegion(testApp.`package`, startingPos) + } + } - override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = mapOf( - ActivityOptions.EXTRA_STARVE_UI_THREAD to configuration.starveUiThread.toString() - ) + @FlakyTest(bugId = 151179149) + @Test + fun focusDoesNotChange() = testSpec.focusDoesNotChange() - private val testFactory = FlickerTestRunnerFactory.getInstance() + companion object { + private val testFactory = FlickerTestParameterFactory.getInstance() private val Bundle.starveUiThread get() = this.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) - private fun Bundle.createConfig(starveUiThread: Boolean): Bundle { - val config = this.deepCopy() + private fun FlickerTestParameter.createConfig(starveUiThread: Boolean): Bundle { + val config = this.config.deepCopy() config.putBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, starveUiThread) return config } @JvmStatic - private fun getConfigurations(): List<Bundle> { - return testFactory.getConfigRotationTests().flatMap { + private fun getConfigurations(): List<FlickerTestParameter> { + return testFactory.getConfigRotationTests(repetitions = 2).flatMap { val defaultRun = it.createConfig(starveUiThread = false) val busyUiRun = it.createConfig(starveUiThread = true) - listOf(defaultRun, busyUiRun) + listOf( + FlickerTestParameter(defaultRun), + FlickerTestParameter(busyUiRun, + name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD" + ) + ) } } @Parameterized.Parameters(name = "{0}") @JvmStatic - fun getParams(): Collection<Array<Any>> { - val configurations = getConfigurations() - val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> - withTestName { - val extra = if (configuration.starveUiThread) { - "BUSY_UI_THREAD" - } else { - "" - } - buildTestTag(configuration, extraInfo = extra) - } - assertions { - val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation) - val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation) - - presubmit { - windowManagerTrace { - visibleWindowsShownMoreThanOneConsecutiveEntry() - appWindowAlwaysVisibleOnTop(testApp.`package`) - } - - layersTrace { - layerAlwaysVisible(testApp.`package`) - } - } - - flaky { - windowManagerTrace { - navBarWindowIsAlwaysVisible(bugId = 140855415) - statusBarWindowIsAlwaysVisible(bugId = 140855415) - } - - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - noUncoveredRegions(configuration.startRotation, - configuration.endRotation, allStates = false, bugId = 147659548) - navBarLayerRotatesAndScales(configuration.startRotation, - configuration.endRotation) - statusBarLayerRotatesScales(configuration.startRotation, - configuration.endRotation) - visibleLayersShownMoreThanOneConsecutiveEntry() - - all("appLayerRotates", bugId = 147659548) { - if (startingBounds == endingBounds) { - this.hasVisibleRegion( - testApp.`package`, startingBounds) - } else { - this.hasVisibleRegion(testApp.`package`, - startingBounds) - .then() - .hasVisibleRegion(testApp.`package`, - endingBounds) - } - } - - all("noUncoveredRegions", bugId = 147659548) { - if (startingBounds == endingBounds) { - this.coversAtLeastRegion(startingBounds) - } else { - this.coversAtLeastRegion(startingBounds) - .then() - .coversAtLeastRegion(endingBounds) - } - } - } - - eventLog { - focusDoesNotChange(bugId = 151179149) - } - } - } - } - - return testFactory.buildRotationTest(instrumentation, transition, testSpec, - deviceConfigurations = configurations, repetitions = 2) + fun getParams(): Collection<FlickerTestParameter> { + return getConfigurations() } } -}
\ No newline at end of file +} diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 95044dc5e7bb..6e1cef496f40 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -105,6 +105,7 @@ apex { key: "com.android.apex.apkrollback.test.key", apps: ["TestAppAv1"], installable: false, + updatable: false, } apex { @@ -115,6 +116,7 @@ apex { key: "com.android.apex.apkrollback.test.key", apps: ["TestAppAv2"], installable: false, + updatable: false, } apex { @@ -125,4 +127,5 @@ apex { key: "com.android.apex.apkrollback.test.key", apps: ["TestAppACrashingV2"], installable: false, + updatable: false, } diff --git a/tests/net/common/java/android/net/NetworkStackTest.java b/tests/net/common/java/android/net/NetworkStackTest.java index a99aa0106655..f8f9c72374ad 100644 --- a/tests/net/common/java/android/net/NetworkStackTest.java +++ b/tests/net/common/java/android/net/NetworkStackTest.java @@ -15,20 +15,8 @@ */ package android.net; -import static android.Manifest.permission.NETWORK_STACK; -import static android.content.pm.PackageManager.PERMISSION_DENIED; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; -import static android.net.NetworkStack.checkNetworkStackPermission; -import static android.net.NetworkStack.checkNetworkStackPermissionOr; - import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.when; -import android.content.Context; import android.os.Build; import android.os.IBinder; @@ -46,44 +34,15 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class NetworkStackTest { - private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"}; - @Rule public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); - @Mock Context mCtx; @Mock private IBinder mConnectorBinder; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } - @Test - public void testCheckNetworkStackPermission() throws Exception { - when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED); - when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) - .thenReturn(PERMISSION_DENIED); - checkNetworkStackPermission(mCtx); - checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); - - when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED); - when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) - .thenReturn(PERMISSION_GRANTED); - checkNetworkStackPermission(mCtx); - checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); - - when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED); - - try { - checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); - } catch (SecurityException e) { - // Expect to get a SecurityException - return; - } - - fail("Expect fail but permission granted."); - } - @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testGetService() { NetworkStack.setServiceForTest(mConnectorBinder); diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 083c8c8741da..9ed55f098a16 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -38,6 +38,7 @@ import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder import android.os.INetworkManagementService +import android.os.SystemConfigManager import android.os.UserHandle import android.testing.TestableContext import android.util.Log @@ -57,6 +58,7 @@ import org.junit.BeforeClass import org.junit.Test import org.junit.runner.RunWith import org.mockito.AdditionalAnswers +import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.anyInt @@ -94,6 +96,8 @@ class ConnectivityServiceIntegrationTest { private lateinit var netd: INetd @Mock private lateinit var dnsResolver: IDnsResolver + @Mock + private lateinit var systemConfigManager: SystemConfigManager @Spy private var context = TestableContext(realContext) @@ -151,6 +155,11 @@ class ConnectivityServiceIntegrationTest { doReturn(UserHandle.ALL).`when`(asUserCtx).user doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt()) doNothing().`when`(context).sendStickyBroadcast(any(), any()) + doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context) + .getSystemServiceName(SystemConfigManager::class.java) + doReturn(systemConfigManager).`when`(context) + .getSystemService(Context.SYSTEM_CONFIG_SERVICE) + doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString()) networkStackClient = TestNetworkStackClient(realContext) networkStackClient.init() diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 24e559225027..6de1075d519b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -53,6 +53,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; @@ -238,6 +239,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.SystemClock; +import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -430,6 +432,7 @@ public class ConnectivityServiceTest { @Mock EthernetManager mEthernetManager; @Mock NetworkPolicyManager mNetworkPolicyManager; @Mock KeyStore mKeyStore; + @Mock SystemConfigManager mSystemConfigManager; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -526,6 +529,7 @@ public class ConnectivityServiceTest { if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager; if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager; if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager; + if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager; return super.getSystemService(name); } @@ -1432,6 +1436,7 @@ public class ConnectivityServiceTest { applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) .thenReturn(applicationInfo); + when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . @@ -2783,7 +2788,8 @@ public class ConnectivityServiceTest { if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS || - capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) { + capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP + || capability == NET_CAPABILITY_ENTERPRISE) { assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); } else { assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); @@ -2882,6 +2888,7 @@ public class ConnectivityServiceTest { tryNetworkFactoryRequests(NET_CAPABILITY_IA); tryNetworkFactoryRequests(NET_CAPABILITY_RCS); tryNetworkFactoryRequests(NET_CAPABILITY_XCAP); + tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE); tryNetworkFactoryRequests(NET_CAPABILITY_EIMS); tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED); tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET); @@ -6847,7 +6854,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) + && caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); @@ -6857,7 +6864,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) + && caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); @@ -7491,7 +7498,7 @@ public class ConnectivityServiceTest { assertNotNull(underlying); mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY); // The legacy lockdown VPN only supports userId 0. - final Set<UidRange> ranges = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.registerAgent(ranges); mMockVpn.setUnderlyingNetworks(new Network[]{underlying}); mMockVpn.connect(true); @@ -8410,7 +8417,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8438,7 +8445,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8454,7 +8461,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8469,7 +8476,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8521,7 +8528,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); + final UidRange vpnRange = createUidRange(PRIMARY_USER); final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -8720,7 +8727,7 @@ public class ConnectivityServiceTest { private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.setVpnType(vpnType); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); @@ -9279,7 +9286,7 @@ public class ConnectivityServiceTest { lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); - final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); + final UidRange vpnRange = createUidRange(PRIMARY_USER); Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -10338,4 +10345,8 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } + + private UidRange createUidRange(int userId) { + return UidRange.createForUser(UserHandle.of(userId)); + } } diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index c86224a71978..32c95f149979 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -16,12 +16,16 @@ package com.android.server; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.INetd.IF_STATE_DOWN; +import static android.net.INetd.IF_STATE_UP; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -36,6 +40,7 @@ import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.INetd; import android.net.InetAddresses; +import android.net.InterfaceConfigurationParcel; import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; @@ -48,7 +53,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.os.Binder; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.system.Os; import android.test.mock.MockContext; @@ -148,10 +152,17 @@ public class IpSecServiceParameterizedTest { } throw new SecurityException("Unavailable permission requested"); } + + @Override + public int checkCallingOrSelfPermission(String permission) { + if (android.Manifest.permission.NETWORK_STACK.equals(permission)) { + return PERMISSION_GRANTED; + } + throw new UnsupportedOperationException(); + } }; INetd mMockNetd; - INetworkManagementService mNetworkManager; PackageManager mMockPkgMgr; IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService mIpSecService; @@ -181,10 +192,9 @@ public class IpSecServiceParameterizedTest { @Before public void setUp() throws Exception { mMockNetd = mock(INetd.class); - mNetworkManager = mock(INetworkManagementService.class); mMockPkgMgr = mock(PackageManager.class); mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class); - mIpSecService = new IpSecService(mMockContext, mNetworkManager, mMockIpSecSrvConfig); + mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig); // Injecting mock netd when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd); @@ -644,7 +654,10 @@ public class IpSecServiceParameterizedTest { } private IpSecTunnelInterfaceResponse createAndValidateTunnel( - String localAddr, String remoteAddr, String pkgName) { + String localAddr, String remoteAddr, String pkgName) throws Exception { + final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel(); + config.flags = new String[] {IF_STATE_DOWN}; + when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config); IpSecTunnelInterfaceResponse createTunnelResp = mIpSecService.createTunnelInterface( mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName); @@ -674,7 +687,8 @@ public class IpSecServiceParameterizedTest { anyInt(), anyInt(), anyInt()); - verify(mNetworkManager).setInterfaceUp(createTunnelResp.interfaceName); + verify(mMockNetd).interfaceSetCfg(argThat( + config -> Arrays.asList(config.flags).contains(IF_STATE_UP))); } @Test diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java index 788e4efe097e..22a2c94fc194 100644 --- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.os.Binder; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.RemoteException; import androidx.test.filters.SmallTest; @@ -62,8 +61,7 @@ public class IpSecServiceRefcountedResourceTest { public void setUp() throws Exception { mMockContext = mock(Context.class); mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class); - mIpSecService = new IpSecService( - mMockContext, mock(INetworkManagementService.class), mMockIpSecSrvConfig); + mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig); } private void assertResourceState( diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index 536e98327e1f..f97eabf6366d 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -42,7 +42,6 @@ import android.net.IpSecManager; import android.net.IpSecSpiResponse; import android.net.IpSecUdpEncapResponse; import android.os.Binder; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.Process; import android.system.ErrnoException; @@ -116,7 +115,6 @@ public class IpSecServiceTest { } Context mMockContext; - INetworkManagementService mMockNetworkManager; INetd mMockNetd; IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService mIpSecService; @@ -124,10 +122,9 @@ public class IpSecServiceTest { @Before public void setUp() throws Exception { mMockContext = mock(Context.class); - mMockNetworkManager = mock(INetworkManagementService.class); mMockNetd = mock(INetd.class); mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class); - mIpSecService = new IpSecService(mMockContext, mMockNetworkManager, mMockIpSecSrvConfig); + mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig); // Injecting mock netd when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd); @@ -135,7 +132,7 @@ public class IpSecServiceTest { @Test public void testIpSecServiceCreate() throws InterruptedException { - IpSecService ipSecSrv = IpSecService.create(mMockContext, mMockNetworkManager); + IpSecService ipSecSrv = IpSecService.create(mMockContext); assertNotNull(ipSecSrv); } @@ -608,7 +605,7 @@ public class IpSecServiceTest { public void testOpenUdpEncapSocketTagsSocket() throws Exception { IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class); IpSecService testIpSecService = new IpSecService( - mMockContext, mMockNetworkManager, mMockIpSecSrvConfig, mockTagger); + mMockContext, mMockIpSecSrvConfig, mockTagger); IpSecUdpEncapResponse udpEncapResp = testIpSecService.openUdpEncapsulationSocket(0, new Binder()); diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 8f5ae97bc4c5..e4e24b464838 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -61,6 +61,7 @@ import android.content.pm.PackageManagerInternal; import android.net.INetd; import android.net.UidRange; import android.os.Build; +import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; import android.util.SparseIntArray; @@ -114,6 +115,7 @@ public class PermissionMonitorTest { @Mock private PackageManagerInternal mMockPmi; @Mock private UserManager mUserManager; @Mock private PermissionMonitor.Dependencies mDeps; + @Mock private SystemConfigManager mSystemConfigManager; private PermissionMonitor mPermissionMonitor; @@ -124,6 +126,11 @@ public class PermissionMonitorTest { when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager); when(mUserManager.getUserHandles(eq(true))).thenReturn( Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 })); + when(mContext.getSystemServiceName(SystemConfigManager.class)) + .thenReturn(Context.SYSTEM_CONFIG_SERVICE); + when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE)) + .thenReturn(mSystemConfigManager); + when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]); mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps)); @@ -747,4 +754,20 @@ public class PermissionMonitorTest { GET_PERMISSIONS | MATCH_ANY_USER); assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); } + + @Test + public void testUpdateUidPermissionsFromSystemConfig() throws Exception { + final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); + when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>()); + when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET))) + .thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 }); + when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS))) + .thenReturn(new int[]{ MOCK_UID2 }); + + mPermissionMonitor.startMonitoring(); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 }); + mNetdServiceMonitor.expectPermission( + INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, + new int[]{ MOCK_UID2 }); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index cffd2d1d428f..7489a0f889dc 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -21,6 +21,8 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_RESTRICTED; import static android.net.ConnectivityManager.NetworkCallback; +import static android.net.INetd.IF_STATE_DOWN; +import static android.net.INetd.IF_STATE_UP; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -62,6 +64,7 @@ import android.net.ConnectivityManager; import android.net.INetd; import android.net.Ikev2VpnProfile; import android.net.InetAddresses; +import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.IpSecTunnelInterfaceResponse; @@ -179,7 +182,8 @@ public class VpnTest { mPackages.put(PKGS[i], PKG_UIDS[i]); } } - private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id); + private static final UidRange PRI_USER_RANGE = + UidRange.createForUser(UserHandle.of(primaryUser.id)); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @@ -269,7 +273,7 @@ public class VpnTest { vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id) + PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id)) })), ranges); } @@ -872,17 +876,28 @@ public class VpnTest { eq(AppOpsManager.MODE_IGNORED)); } - private NetworkCallback triggerOnAvailableAndGetCallback() { + private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception { final ArgumentCaptor<NetworkCallback> networkCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class); verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)) .requestNetwork(any(), networkCallbackCaptor.capture()); + // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be + // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException. + final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel(); + config.flags = new String[] {IF_STATE_DOWN}; + when(mNetd.interfaceGetCfg(anyString())).thenReturn(config); final NetworkCallback cb = networkCallbackCaptor.getValue(); cb.onAvailable(TEST_NETWORK); return cb; } + private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception { + // Add a timeout for waiting for interfaceSetCfg to be called. + verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat( + config -> Arrays.asList(config.flags).contains(flag))); + } + @Test public void testStartPlatformVpnAuthenticationFailed() throws Exception { final ArgumentCaptor<IkeSessionCallback> captor = @@ -894,6 +909,8 @@ public class VpnTest { final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile)); final NetworkCallback cb = triggerOnAvailableAndGetCallback(); + verifyInterfaceSetCfgWithFlags(IF_STATE_UP); + // Wait for createIkeSession() to be called before proceeding in order to ensure consistent // state verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)) @@ -912,6 +929,8 @@ public class VpnTest { final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile); final NetworkCallback cb = triggerOnAvailableAndGetCallback(); + verifyInterfaceSetCfgWithFlags(IF_STATE_UP); + // Wait for createIkeSession() to be called before proceeding in order to ensure consistent // state verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb)); diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index 708767605508..66590c92579b 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -16,6 +16,8 @@ package android.net.vcn; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; + import static androidx.test.InstrumentationRegistry.getContext; import static org.junit.Assert.assertEquals; @@ -204,10 +206,13 @@ public class VcnManagerTest { cbBinder.onEnteredSafeMode(); verify(mMockStatusCallback).onEnteredSafeMode(); + cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, - "java.net.UnknownHostException", + UnknownHostException.class.getName(), "exception_message"); verify(mMockStatusCallback) .onGatewayConnectionError( diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java index 3ba0a1f53a9f..a674425efea3 100644 --- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java +++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -46,6 +46,6 @@ public class VcnUnderlyingNetworkPolicyTest { @Test public void testParcelUnparcel() { - assertParcelSane(SAMPLE_NETWORK_POLICY, 2); + assertParcelSane(SAMPLE_NETWORK_POLICY, 1); } } diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 45b2381ce06d..9b500a7271d7 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -43,7 +43,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,6 +58,7 @@ import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.IBinder; @@ -783,7 +783,7 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, times(1)).onEnteredSafeMode(); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -795,7 +795,8 @@ public class VcnManagementServiceTest { false /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -807,7 +808,8 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, false /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test |